Skip to content
This repository was archived by the owner on Oct 15, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
# 4.7.1
# 5.0.0 (Unreleased)
#### Notes
Major release where the resource file is revamped, so that it can be used to instantiate the resource object.
Addition helper methods where necessary to make the sdk more user friendly and to reduce the dependency on hard coded values.

#### Breaking changes
Resource file now instantiates the object, which is used to directly call the available methods.

#### Features supported with current release:
- Firmware Bundle

#### Bug fixes
- [#364] (https://github.com/HewlettPackard/python-hpOneView/issues/364) Bug in index_resources.get_all()

Expand Down
2 changes: 1 addition & 1 deletion endpoints-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
|<sub>/rest/fcoe-networks/{id}</sub> | PUT | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark:
|<sub>/rest/fcoe-networks/{id}</sub> | DELETE | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark:
| **Firmware Bundles** |
|<sub>/rest/firmware-bundles</sub> | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|<sub>/rest/firmware-bundles</sub> | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| **Firmware Drivers** |
|<sub>/rest/firmware-drivers</sub> | GET | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|<sub>/rest/firmware-drivers</sub> | POST | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Expand Down
7 changes: 5 additions & 2 deletions examples/firmware_bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,15 @@
# To run this example you must define a path to a valid file
firmware_path = "<path_to_firmware_bundle>"

# Use the below option to specify additional request headers as required
custom_headers = {'initialScopeUris': '<Scope_Uris>'}

# Try load config from a file (if there is a config file)
config = try_load_from_file(config)
oneview_client = OneViewClient(config)

# Upload a firmware bundle
print("\nUpload a firmware bundle")
firmware_bundle_information = oneview_client.firmware_bundles.upload(file_path=firmware_path)
firmware_bundle_information = oneview_client.firmware_bundles.upload(file_path=firmware_path, custom_headers=custom_headers)
print("\n Upload successful! Firmware information returned: \n")
pprint(firmware_bundle_information)
pprint(firmware_bundle_information['name'])
7 changes: 4 additions & 3 deletions hpOneView/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ def encode_multipart_formdata(self, fields, files, baseName, verbose=False):
fin.close()
return content_type

def post_multipart_with_response_handling(self, uri, file_path, baseName):
resp, body = self.post_multipart(uri, None, file_path, baseName)
def post_multipart_with_response_handling(self, uri, file_path, baseName, custom_headers):
resp, body = self.post_multipart(uri, None, file_path, baseName, custom_headers)

if resp.status == 202:
task = self.__get_task_from_response(resp, body)
Expand All @@ -283,7 +283,7 @@ def post_multipart_with_response_handling(self, uri, file_path, baseName):

return None, body

def post_multipart(self, uri, fields, files, baseName, verbose=False):
def post_multipart(self, uri, fields, files, baseName, verbose=False, custom_headers=None):
content_type = self.encode_multipart_formdata(fields, files, baseName,
verbose)
inputfile = self._open(files + '.b64', 'rb')
Expand All @@ -295,6 +295,7 @@ def post_multipart(self, uri, fields, files, baseName, verbose=False):
conn.connect()
conn.putrequest('POST', uri)
conn.putheader('uploadfilename', baseName)
conn.putheader('initialScopeUris', custom_headers['initialScopeUris'])
conn.putheader('auth', self._headers['auth'])
conn.putheader('Content-Type', content_type)
totalSize = os.path.getsize(files + '.b64')
Expand Down
4 changes: 1 addition & 3 deletions hpOneView/oneview_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -905,9 +905,7 @@ def firmware_bundles(self):
Returns:
FirmwareBundles:
"""
if not self.__firmware_bundles:
self.__firmware_bundles = FirmwareBundles(self.__connection)
return self.__firmware_bundles
return FirmwareBundles(self.__connection)

@property
def uplink_sets(self):
Expand Down
6 changes: 4 additions & 2 deletions hpOneView/resources/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -1209,7 +1209,7 @@ def create(self, resource, uri=None, timeout=-1, custom_headers=None, default_va

return self.__do_post(uri, resource, timeout, custom_headers)

def upload(self, file_path, uri=None, timeout=-1):
def upload(self, file_path, uri=None, timeout=-1, custom_headers=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add documentation for the new arg in the comments section

"""
Makes a multipart request.

Expand All @@ -1221,6 +1221,8 @@ def upload(self, file_path, uri=None, timeout=-1):
timeout:
Timeout in seconds. Wait for task completion by default. The timeout does not abort the operation
in OneView; it just stops waiting for its completion.
custom_headers:
Allows set specific HTTP headers.

Returns:
dict: Response body.
Expand All @@ -1229,7 +1231,7 @@ def upload(self, file_path, uri=None, timeout=-1):
uri = self._uri

upload_file_name = os.path.basename(file_path)
task, entity = self._connection.post_multipart_with_response_handling(uri, file_path, upload_file_name)
task, entity = self._connection.post_multipart_with_response_handling(uri, file_path, upload_file_name, custom_headers)

if not task:
return entity
Expand Down
5 changes: 3 additions & 2 deletions hpOneView/resources/settings/firmware_bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def __init__(self, con):
self._connection = con
self._client = ResourceClient(con, self.URI)

def upload(self, file_path, timeout=-1):
def upload(self, file_path, timeout=-1, custom_headers=None):
"""
Upload an SPP ISO image file or a hotfix file to the appliance.
The API supports upload of one hotfix at a time into the system.
Expand All @@ -59,4 +59,5 @@ def upload(self, file_path, timeout=-1):
Returns:
dict: Information about the updated firmware bundle.
"""
return self._client.upload(file_path, timeout=timeout)
# custom_headers = { 'initialScopeUris': '/rest/scopes/bf3e77e3-3248-41b3-aaee-5d83b6ac4b49'}
return self._client.upload(file_path, timeout=timeout, custom_headers=custom_headers)
2 changes: 1 addition & 1 deletion tests/unit/resources/settings/test_firmware_bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ def test_upload(self, mock_upload):

self._firmware_bundles.upload(firmware_path)

mock_upload.assert_called_once_with(firmware_path, timeout=-1)
mock_upload.assert_called_once_with(firmware_path, timeout=-1, custom_headers=None)
4 changes: 2 additions & 2 deletions tests/unit/resources/test_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,7 @@ def test_upload_should_call_post_multipart(self, mock_post_multipart):

self.resource_client.upload(filepath, uri)

mock_post_multipart.assert_called_once_with(uri, filepath, 'SPPgen9snap6.2015_0405.81.iso')
mock_post_multipart.assert_called_once_with(uri, filepath, 'SPPgen9snap6.2015_0405.81.iso', None)

@mock.patch.object(connection, 'post_multipart_with_response_handling')
def test_upload_should_call_post_multipart_with_resource_uri_when_not_uri_provided(self, mock_post_multipart):
Expand All @@ -1226,7 +1226,7 @@ def test_upload_should_call_post_multipart_with_resource_uri_when_not_uri_provid

self.resource_client.upload(filepath)

mock_post_multipart.assert_called_once_with('/rest/testuri', mock.ANY, mock.ANY)
mock_post_multipart.assert_called_once_with('/rest/testuri', mock.ANY, mock.ANY, mock.ANY)

@mock.patch.object(connection, 'post_multipart_with_response_handling')
@mock.patch.object(TaskMonitor, 'wait_for_task')
Expand Down
17 changes: 13 additions & 4 deletions tests/unit/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@ def test_post_multipart_should_put_request(self, mock_rm, mock_path_size, mock_c
self.connection.post_multipart(uri='/rest/resources/',
fields=None,
files="/a/path/filename.zip",
custom_headers={'initialScopeUris': '/rest/scopes/fake'},
baseName="archive.zip")

internal_conn = self.connection.get_connection.return_value
Expand All @@ -646,10 +647,12 @@ def test_post_multipart_should_put_headers(self, mock_rm, mock_path_size, mock_c
self.connection.post_multipart(uri='/rest/resources/',
fields=None,
files="/a/path/filename.zip",
custom_headers={'initialScopeUris': '/rest/scopes/fake'},
baseName="archive.zip")

expected_putheader_calls = [
call('uploadfilename', 'archive.zip'),
call(u'initialScopeUris', '/rest/scopes/fake'),
call('auth', 'LTIxNjUzMjc0OTUzzHoF7eEkZLEUWVA-fuOZP4VGA3U8e67E'),
call('Content-Type', 'multipart/form-data; boundary=----------ThIs_Is_tHe_bouNdaRY_$'),
call('Content-Length', 2621440),
Expand All @@ -669,6 +672,7 @@ def test_post_multipart_should_read_file_in_chunks_of_1mb(self, mock_rm, mock_pa
self.connection.post_multipart(uri='/rest/resources/',
fields=None,
files="/a/path/filename.zip",
custom_headers={'initialScopeUris': '/rest/scopes/fake'},
baseName="archive.zip")

expected_mmap_read_calls = [
Expand All @@ -689,6 +693,7 @@ def test_post_multipart_should_send_file_in_chuncks_of_1mb(self, mock_rm, mock_p
self.connection.post_multipart(uri='/rest/resources/',
fields=None,
files="/a/path/filename.zip",
custom_headers={'initialScopeUris': '/rest/scopes/fake'},
baseName="archive.zip")

expected_conn_send_calls = [
Expand All @@ -710,6 +715,7 @@ def test_post_multipart_should_remove_temp_encoded_file(self, mock_rm, mock_path
self.connection.post_multipart(uri='/rest/resources/',
fields=None,
files="/a/path/filename.zip",
custom_headers={'initialScopeUris': '/rest/scopes/fake'},
baseName="archive.zip")

mock_rm.assert_called_once_with('/a/path/filename.zip.b64')
Expand All @@ -727,6 +733,7 @@ def test_post_multipart_should_raise_exception_when_response_status_400(self, mo
self.connection.post_multipart(uri='/rest/resources/',
fields=None,
files="/a/path/filename.zip",
custom_headers={'initialScopeUris': '/rest/scopes/fake'},
baseName="archive.zip")
except HPOneViewException as e:
self.assertEqual(e.msg, "An error occurred.")
Expand All @@ -745,6 +752,7 @@ def test_post_multipart_should_return_response_and_body_when_response_status_200
response, body = self.connection.post_multipart(uri='/rest/resources/',
fields=None,
files="/a/path/filename.zip",
custom_headers={'initialScopeUris': '/rest/scopes/fake'},
baseName="archive.zip")

self.assertEqual(body, self.expected_response_body)
Expand All @@ -764,6 +772,7 @@ def test_post_multipart_should_handle_json_load_exception(self, mock_json_loads,
response, body = self.connection.post_multipart(uri='/rest/resources/',
fields=None,
files="/a/path/filename.zip",
custom_headers={'initialScopeUris': '/rest/scopes/fake'},
baseName="archive.zip")

self.assertTrue(body)
Expand All @@ -775,7 +784,7 @@ def test_post_multipart_with_response_handling_when_status_202_without_task(self
mock_response.getheader.return_value = None
mock_post_multipart.return_value = mock_response, "content"

task, body = self.connection.post_multipart_with_response_handling("uri", "filepath", "basename")
task, body = self.connection.post_multipart_with_response_handling("uri", "filepath", "custom_headers", "basename")

self.assertFalse(task)
self.assertEqual(body, "content")
Expand All @@ -789,7 +798,7 @@ def test_post_multipart_with_response_handling_when_status_202_with_task(self, m
mock_post_multipart.return_value = mock_response, "content"
mock_get.return_value = fake_task

task, body = self.connection.post_multipart_with_response_handling("uri", "filepath", "basename")
task, body = self.connection.post_multipart_with_response_handling("uri", "filepath", "custom_headers", "basename")

self.assertEqual(task, fake_task)
self.assertEqual(body, "content")
Expand All @@ -799,7 +808,7 @@ def test_post_multipart_with_response_handling_when_status_200_and_body_is_task(
fake_task = {"category": "tasks"}
mock_post_multipart.return_value = Mock(status=200), fake_task

task, body = self.connection.post_multipart_with_response_handling("uri", "filepath", "basename")
task, body = self.connection.post_multipart_with_response_handling("uri", "filepath", "custom_headers", "basename")

self.assertEqual(task, fake_task)
self.assertEqual(body, fake_task)
Expand All @@ -808,7 +817,7 @@ def test_post_multipart_with_response_handling_when_status_200_and_body_is_task(
def test_post_multipart_with_response_handling_when_status_200_and_body_is_not_task(self, mock_post_multipart):
mock_post_multipart.return_value = Mock(status=200), "content"

task, body = self.connection.post_multipart_with_response_handling("uri", "filepath", "basename")
task, body = self.connection.post_multipart_with_response_handling("uri", "filepath", "custom_headers", "basename")

self.assertFalse(task)
self.assertEqual(body, "content")
Expand Down
9 changes: 6 additions & 3 deletions tests/unit/test_oneview_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
from hpOneView.resources.settings.appliance_node_information import ApplianceNodeInformation
from hpOneView.resources.settings.appliance_time_and_locale_configuration import ApplianceTimeAndLocaleConfiguration
from hpOneView.resources.settings.versions import Versions
from hpOneView.resources.settings.firmware_bundles import FirmwareBundles
from tests.test_utils import mock_builtin
from hpOneView.resources.settings.licenses import Licenses

Expand Down Expand Up @@ -566,9 +567,11 @@ def test_lazy_loading_firmware_drivers(self):
firmware_drivers = self._oneview.firmware_drivers
self.assertEqual(firmware_drivers, self._oneview.firmware_drivers)

def test_lazy_loading_firmware_bundles(self):
firmware_bundles = self._oneview.firmware_bundles
self.assertEqual(firmware_bundles, self._oneview.firmware_bundles)
def test_firmware_bundles_has_right_type(self):
self.assertIsInstance(self._oneview.firmware_bundles, FirmwareBundles)

def test_firmware_bundles_has_value(self):
self.assertIsNotNone(self._oneview.firmware_bundles)

def test_migratable_vc_domains_has_right_type(self):
self.assertIsInstance(self._oneview.migratable_vc_domains, MigratableVcDomains)
Expand Down