Merge "Add support for the `UpdateService` resource"
This commit is contained in:
commit
0b3241b0bd
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for the UpdateService resource to the library.
|
||||
`UpdateService` is responsible for managing firmware updates.
|
|
@ -24,6 +24,7 @@ from sushy.resources.registry import message_registry_file
|
|||
from sushy.resources.sessionservice import session
|
||||
from sushy.resources.sessionservice import sessionservice
|
||||
from sushy.resources.system import system
|
||||
from sushy.resources.updateservice import updateservice
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -79,6 +80,9 @@ class Sushy(base.ResourceBase):
|
|||
_registries_path = base.Field(['Registries', '@odata.id'])
|
||||
"""Registries path"""
|
||||
|
||||
_update_service_path = base.Field(['UpdateService', '@odata.id'])
|
||||
"""UpdateService path"""
|
||||
|
||||
def __init__(self, base_url, username=None, password=None,
|
||||
root_prefix='/redfish/v1/', verify=True,
|
||||
auth=None, connector=None):
|
||||
|
@ -226,6 +230,19 @@ class Sushy(base.ResourceBase):
|
|||
return session.Session(self._conn, identity,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
def get_update_service(self):
|
||||
"""Get the UpdateService object
|
||||
|
||||
:returns: The UpdateService object
|
||||
"""
|
||||
if not self._update_service_path:
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute='UpdateService/@odata.id', resource=self._path)
|
||||
|
||||
return updateservice.UpdateService(
|
||||
self._conn, self._update_service_path,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
def _get_registry_collection(self):
|
||||
"""Get MessageRegistryFileCollection object
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# Values come from the Redfish UpdateService json-schema.
|
||||
# https://redfish.dmtf.org/schemas/UpdateService.v1_2_2.json
|
||||
|
||||
# Transfer Protocol Type constants
|
||||
|
||||
TRANSFER_PROTOCOL_TYPE_CIFS = 'CIFS'
|
||||
TRANSFER_PROTOCOL_TYPE_FTP = 'FTP'
|
||||
TRANSFER_PROTOCOL_TYPE_SFTP = 'SFTP'
|
||||
TRANSFER_PROTOCOL_TYPE_HTTP = 'HTTP'
|
||||
TRANSFER_PROTOCOL_TYPE_HTTPS = 'HTTPS'
|
||||
TRANSFER_PROTOCOL_TYPE_SCP = 'SCP'
|
||||
TRANSFER_PROTOCOL_TYPE_TFTP = 'TFTP'
|
||||
TRANSFER_PROTOCOL_TYPE_OEM = 'OEM'
|
||||
TRANSFER_PROTOCOL_TYPE_NFS = 'NFS'
|
|
@ -0,0 +1,35 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from sushy.resources.updateservice import constants as ups_cons
|
||||
from sushy import utils
|
||||
|
||||
|
||||
TRANSFER_PROTOCOL_TYPE_VALUE_MAP = {
|
||||
'Common Internet File System Protocol':
|
||||
ups_cons.TRANSFER_PROTOCOL_TYPE_CIFS,
|
||||
'File Transfer Protocol': ups_cons.TRANSFER_PROTOCOL_TYPE_FTP,
|
||||
'Secure File Transfer Protocol': ups_cons.TRANSFER_PROTOCOL_TYPE_SFTP,
|
||||
'Hypertext Transfer Protocol': ups_cons.TRANSFER_PROTOCOL_TYPE_HTTP,
|
||||
'HTTP Secure Protocol': ups_cons.TRANSFER_PROTOCOL_TYPE_HTTPS,
|
||||
'Secure File Copy Protocol': ups_cons.TRANSFER_PROTOCOL_TYPE_SCP,
|
||||
'Trivial File Transfer Protocol': ups_cons.TRANSFER_PROTOCOL_TYPE_TFTP,
|
||||
'A protocol defined by the manufacturer':
|
||||
ups_cons.TRANSFER_PROTOCOL_TYPE_OEM,
|
||||
'Network File System Protocol': ups_cons.TRANSFER_PROTOCOL_TYPE_NFS
|
||||
}
|
||||
|
||||
TRANSFER_PROTOCOL_TYPE_VALUE_MAP_REV = (
|
||||
utils.revert_dictionary(TRANSFER_PROTOCOL_TYPE_VALUE_MAP))
|
||||
|
||||
TRANSFER_PROTOCOL_TYPE_VALUE_MAP[
|
||||
'Network File System Protocol'] = ups_cons.TRANSFER_PROTOCOL_TYPE_NFS
|
|
@ -0,0 +1,96 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# This is referred from Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/SoftwareInventory.v1_2_0.json
|
||||
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SoftwareInventory(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The software inventory identity"""
|
||||
|
||||
lowest_supported_version = base.Field('LowestSupportedVersion')
|
||||
"""The lowest supported version of the software"""
|
||||
|
||||
manufacturer = base.Field('Manufacturer')
|
||||
"""The manufacturer of the software"""
|
||||
|
||||
name = base.Field('Name', required=True)
|
||||
"""The software inventory name"""
|
||||
|
||||
release_date = base.Field('ReleaseDate')
|
||||
"""Release date of the software"""
|
||||
|
||||
related_item = base.Field('RelatedItem')
|
||||
"""The ID(s) of the resources associated with the software inventory
|
||||
item"""
|
||||
|
||||
status = common.StatusField('Status')
|
||||
"""The status of the software inventory"""
|
||||
|
||||
software_id = base.Field('SoftwareId')
|
||||
"""The identity of the software"""
|
||||
|
||||
uefi_device_paths = base.Field('UefiDevicePaths')
|
||||
"""Represents the UEFI Device Path(s)"""
|
||||
|
||||
updateable = base.Field('Updateable')
|
||||
"""Indicates whether this software can be updated by the update
|
||||
service"""
|
||||
|
||||
version = base.Field('Version')
|
||||
"""The version of the software"""
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a SoftwareInventory
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the SoftwareInventory resources
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version.
|
||||
"""
|
||||
super(SoftwareInventory, self).__init__(
|
||||
connector,
|
||||
identity,
|
||||
redfish_version)
|
||||
|
||||
|
||||
class SoftwareInventoryCollection(base.ResourceCollectionBase):
|
||||
|
||||
name = base.Field('Name')
|
||||
"""The software inventory collection name"""
|
||||
|
||||
description = base.Field('Description')
|
||||
"""The software inventory collection description"""
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return SoftwareInventory
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a SoftwareInventoryCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of SoftwareInventory resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version.
|
||||
"""
|
||||
super(SoftwareInventoryCollection, self).__init__(
|
||||
connector, identity, redfish_version)
|
|
@ -0,0 +1,155 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This is referred from Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/UpdateService.v1_2_2.json
|
||||
|
||||
import logging
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
from sushy.resources.updateservice import mappings as up_maps
|
||||
from sushy.resources.updateservice import softwareinventory
|
||||
from sushy import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SimpleUpdateActionField(common.ActionField):
|
||||
|
||||
image_uri = base.Field('ImageURI')
|
||||
"""The URI of the software image to be installed"""
|
||||
|
||||
targets = base.Field('Targets')
|
||||
"""The array of URIs indicating where the update image is to be""" + \
|
||||
"""applied"""
|
||||
|
||||
transfer_protocol = base.MappedField(
|
||||
'TransferProtocol',
|
||||
up_maps.TRANSFER_PROTOCOL_TYPE_VALUE_MAP)
|
||||
"""The network protocol used by the Update Service"""
|
||||
|
||||
|
||||
class ActionsField(base.CompositeField):
|
||||
|
||||
simple_update = SimpleUpdateActionField(
|
||||
'#UpdateService.SimpleUpdate')
|
||||
|
||||
|
||||
class UpdateService(base.ResourceBase):
|
||||
|
||||
identity = base.Field('Id', required=True)
|
||||
"""The update service identity"""
|
||||
|
||||
http_push_uri = base.Field('HttpPushUri')
|
||||
"""The URI used to perform an HTTP or HTTPS push update to the Update
|
||||
Service"""
|
||||
|
||||
http_push_uri_targets = base.Field('HttpPushUriTargets')
|
||||
"""The array of URIs indicating the target for applying the""" + \
|
||||
"""update image"""
|
||||
|
||||
http_push_uri_targets_busy = base.Field('HttpPushUriTargetsBusy')
|
||||
"""This represents if the HttpPushUriTargets property is reserved""" + \
|
||||
"""by anyclient"""
|
||||
|
||||
name = base.Field('Name', required=True)
|
||||
"""The update service name"""
|
||||
|
||||
service_enabled = base.Field('ServiceEnabled')
|
||||
"""The status of whether this service is enabled"""
|
||||
|
||||
status = common.StatusField('Status')
|
||||
"""The status of the update service"""
|
||||
|
||||
_actions = ActionsField('Actions', required=True)
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a UpdateService
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the UpdateService resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of given version
|
||||
"""
|
||||
super(UpdateService, self).__init__(
|
||||
connector,
|
||||
identity,
|
||||
redfish_version)
|
||||
|
||||
def _get_simple_update_element(self):
|
||||
simple_update_action = self._actions.simple_update
|
||||
if not simple_update_action:
|
||||
raise exceptions.MissingAttributeError(
|
||||
action='#UpdateService.SimpleUpdate',
|
||||
resource=self._path)
|
||||
return simple_update_action
|
||||
|
||||
def get_allowed_transfer_protocol_values(self):
|
||||
"""Get the allowed values for transfer protocol.
|
||||
|
||||
:returns: A set of allowed values.
|
||||
:raises: MissingAttributeError, if Actions/#UpdateService.SimpleUpdate
|
||||
attribute not present.
|
||||
"""
|
||||
simple_update_action = self._get_simple_update_element()
|
||||
|
||||
if not simple_update_action.transfer_protocol:
|
||||
LOG.warning(
|
||||
'Could not figure out the allowed values for the simple '
|
||||
'update action for UpdateService %s', self.identity)
|
||||
return set(up_maps.TRANSFER_PROTOCOL_TYPE_VALUE_MAP_REV)
|
||||
|
||||
return set(up_maps.TRANSFER_PROTOCOL_TYPE_VALUE_MAP[v] for v in
|
||||
simple_update_action.transfer_protocol if v in
|
||||
up_maps.TRANSFER_PROTOCOL_TYPE_VALUE_MAP)
|
||||
|
||||
def simple_update(self, image_uri, targets, transfer_protocol):
|
||||
"""Simple Update is used to update software components"""
|
||||
transfer_protocol = transfer_protocol
|
||||
|
||||
valid_transfer_protocols = self.get_allowed_transfer_protocol_values()
|
||||
if transfer_protocol not in valid_transfer_protocols:
|
||||
raise exceptions.InvalidParameterValueError(
|
||||
parameter='transfer_protocol', value=transfer_protocol,
|
||||
valid_values=valid_transfer_protocols)
|
||||
|
||||
self._conn.post(data={
|
||||
'ImageURI': image_uri,
|
||||
'Targets': targets,
|
||||
'TransferProtocol': transfer_protocol})
|
||||
|
||||
def _get_software_inventory_collection_path(self):
|
||||
"""Helper function to find the SoftwareInventoryCollections path"""
|
||||
soft_inv_col = self.json.get('SoftwareInventory')
|
||||
if not soft_inv_col:
|
||||
raise exceptions.MissingAttributeError(
|
||||
attribute='SoftwareInventory', resource=self._path)
|
||||
return soft_inv_col.get('@odata.id')
|
||||
|
||||
@property
|
||||
@utils.cache_it
|
||||
def software_inventory(self):
|
||||
"""Property to reference SoftwareInventoryCollection instance"""
|
||||
return softwareinventory.SoftwareInventoryCollection(
|
||||
self._conn, self._get_software_inventory_collection_path,
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
@property
|
||||
@utils.cache_it
|
||||
def firmware_inventory(self):
|
||||
"""Property to reference SoftwareInventoryCollection instance"""
|
||||
return softwareinventory.SoftwareInventoryCollection(
|
||||
self._conn, self._get_software_inventory_collection_path,
|
||||
redfish_version=self.redfish_version)
|
|
@ -27,6 +27,9 @@
|
|||
"SessionService": {
|
||||
"@odata.id": "/redfish/v1/SessionService"
|
||||
},
|
||||
"UpdateService": {
|
||||
"@odata.id": "/redfish/v1/UpdateService"
|
||||
},
|
||||
"AccountService": {
|
||||
"@odata.id": "/redfish/v1/AccountService"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"@odata.type": "#SoftwareInventory.v1_2_0.SoftwareInventory",
|
||||
"Id": "BMC",
|
||||
"Name": "Contoso BMC Firmware",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"Updateable": true,
|
||||
"Manufacturer": "Contoso",
|
||||
"ReleaseDate": "2017-08-22T12:00:00",
|
||||
"Version": "1.45.455b66-rev4",
|
||||
"SoftwareId": "1624A9DF-5E13-47FC-874A-DF3AFF143089",
|
||||
"LowestSupportedVersion": "1.30.367a12-rev1",
|
||||
"UefiDevicePaths": [
|
||||
"BMC(0x1,0x0ABCDEF)"
|
||||
],
|
||||
"RelatedItem": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Managers/1"
|
||||
}
|
||||
],
|
||||
"Actions": {
|
||||
"Oem": {}
|
||||
},
|
||||
"Oem": {},
|
||||
"@odata.context": "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory",
|
||||
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/BMC"
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"@odata.type": "#SoftwareInventoryCollection.v1_4_0.SoftwareInventoryCollection",
|
||||
"@odata.id": "/redfish/v1/UpdateService/SoftwareInventory",
|
||||
"Name": "Software Inventory Collection",
|
||||
"Members@odata.count": 2,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/UpdateService/SoftwareInventory"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"@odata.type": "#UpdateService.v1_2_1.UpdateService",
|
||||
"Id": "UpdateService",
|
||||
"Name": "Update service",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK",
|
||||
"HealthRollup": "OK"
|
||||
},
|
||||
"ServiceEnabled": true,
|
||||
"HttpPushUri": "/FWUpdate",
|
||||
"HttpPushUriTargets": ["/FWUpdate"],
|
||||
"HttpPushUriTargetsBusy": false,
|
||||
"FirmwareInventory": {
|
||||
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory"
|
||||
},
|
||||
"SoftwareInventory": {
|
||||
"@odata.id": "/redfish/v1/UpdateService/SoftwareInventory"
|
||||
},
|
||||
"Actions": {
|
||||
"#UpdateService.SimpleUpdate": {
|
||||
"target": "/redfish/v1/UpdateService/Actions/SimpleUpdate",
|
||||
"@Redfish.ActionInfo": "/redfish/v1/UpdateService/SimpleUpdateActionInfo"
|
||||
},
|
||||
"Oem": {}
|
||||
},
|
||||
"Oem": {},
|
||||
"@odata.context": "/redfish/v1/$metadata#UpdateService.UpdateService",
|
||||
"@odata.id": "/redfish/v1/UpdateService"
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import mock
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import constants as res_cons
|
||||
from sushy.resources.updateservice import softwareinventory
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class SoftwareInventoryTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SoftwareInventoryTestCase, self).setUp()
|
||||
conn = mock.Mock()
|
||||
with open(
|
||||
'sushy/tests/unit/json_samples/softwareinventory.json') as f:
|
||||
conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.soft_inv = softwareinventory.SoftwareInventory(
|
||||
conn,
|
||||
'/redfish/v1/UpdateService/SoftwareInventory/1',
|
||||
redfish_version='1.3.0')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.soft_inv._parse_attributes()
|
||||
self.assertEqual('BMC', self.soft_inv.identity)
|
||||
self.assertEqual(
|
||||
'1.30.367a12-rev1',
|
||||
self.soft_inv.lowest_supported_version)
|
||||
self.assertEqual('Contoso', self.soft_inv.manufacturer)
|
||||
self.assertEqual('Contoso BMC Firmware', self.soft_inv.name)
|
||||
self.assertEqual('2017-08-22T12:00:00', self.soft_inv.release_date)
|
||||
self.assertEqual(
|
||||
res_cons.STATE_ENABLED,
|
||||
self.soft_inv.status.state)
|
||||
self.assertEqual(res_cons.HEALTH_OK, self.soft_inv.status.health)
|
||||
self.assertEqual(
|
||||
'1624A9DF-5E13-47FC-874A-DF3AFF143089',
|
||||
self.soft_inv.software_id)
|
||||
self.assertTrue(self.soft_inv.updateable)
|
||||
self.assertEqual('1.45.455b66-rev4', self.soft_inv.version)
|
||||
|
||||
def test__parse_attributes_missing_identity(self):
|
||||
self.soft_inv.json.pop('Id')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Id',
|
||||
self.soft_inv._parse_attributes)
|
||||
|
||||
|
||||
class SoftwareInventoryCollectionTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SoftwareInventoryCollectionTestCase, self).setUp()
|
||||
conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'softwareinventory_collection.json') as f:
|
||||
conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.soft_inv_col = softwareinventory.SoftwareInventoryCollection(
|
||||
conn, '/redfish/v1/UpdateService/SoftwareInventory',
|
||||
redfish_version='1.3.0')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.soft_inv_col._parse_attributes()
|
||||
self.assertEqual('1.3.0', self.soft_inv_col.redfish_version)
|
||||
self.assertEqual(
|
||||
'Software Inventory Collection',
|
||||
self.soft_inv_col.name)
|
||||
|
||||
@mock.patch.object(
|
||||
softwareinventory, 'SoftwareInventory', autospec=True)
|
||||
def test_get_member(self, mock_softwareinventory):
|
||||
path = '/redfish/v1/UpdateService/SoftwareInventory/1'
|
||||
self.soft_inv_col.get_member(path)
|
||||
mock_softwareinventory.assert_called_once_with(
|
||||
self.soft_inv_col._conn, path,
|
||||
redfish_version=self.soft_inv_col.redfish_version)
|
|
@ -0,0 +1,106 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import mock
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import constants as res_cons
|
||||
from sushy.resources.updateservice import constants as ups_cons
|
||||
from sushy.resources.updateservice import softwareinventory
|
||||
from sushy.resources.updateservice import updateservice
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class UpdateServiceTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(UpdateServiceTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/updateservice.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
|
||||
self.upd_serv = updateservice.UpdateService(
|
||||
self.conn, '/redfish/v1/UpdateService/UpdateService',
|
||||
redfish_version='1.3.0')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.upd_serv._parse_attributes()
|
||||
self.assertEqual('UpdateService', self.upd_serv.identity)
|
||||
self.assertEqual('/FWUpdate', self.upd_serv.http_push_uri)
|
||||
self.assertIn('/FWUpdate', self.upd_serv.http_push_uri_targets)
|
||||
self.assertFalse(self.upd_serv.http_push_uri_targets_busy)
|
||||
self.assertEqual('Update service', self.upd_serv.name)
|
||||
self.assertTrue(self.upd_serv.service_enabled)
|
||||
self.assertEqual(res_cons.STATE_ENABLED, self.upd_serv.status.state)
|
||||
self.assertEqual(res_cons.HEALTH_OK, self.upd_serv.status.health)
|
||||
self.assertEqual(
|
||||
res_cons.HEALTH_OK,
|
||||
self.upd_serv.status.health_rollup)
|
||||
|
||||
def test__parse_attributes_missing_actions(self):
|
||||
self.upd_serv.json.pop('Actions')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Actions',
|
||||
self.upd_serv._parse_attributes)
|
||||
|
||||
def test_simple_update(self):
|
||||
self.upd_serv.simple_update(
|
||||
image_uri='local.server/update.exe',
|
||||
targets='/redfish/v1/UpdateService/Actions/SimpleUpdate',
|
||||
transfer_protocol=ups_cons.TRANSFER_PROTOCOL_TYPE_HTTPS)
|
||||
self.upd_serv._conn.post.assert_called_once_with(
|
||||
data={
|
||||
'ImageURI': 'local.server/update.exe',
|
||||
'Targets': '/redfish/v1/UpdateService/Actions/SimpleUpdate',
|
||||
'TransferProtocol': 'HTTPS'})
|
||||
|
||||
def test_software_inventory(self):
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'softwareinventory_collection.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
# | WHEN |
|
||||
actual_software_inventory = self.upd_serv.software_inventory
|
||||
# | THEN |
|
||||
self.assertIsInstance(actual_software_inventory,
|
||||
softwareinventory.SoftwareInventoryCollection)
|
||||
self.conn.get.return_value.json.assert_called_once_with()
|
||||
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
# | WHEN & THEN |
|
||||
self.assertIs(actual_software_inventory,
|
||||
self.upd_serv.software_inventory)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_firmware_inventory(self):
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'softwareinventory_collection.json') as f:
|
||||
self.conn.get.return_value.json.return_value = json.load(f)
|
||||
# | WHEN |
|
||||
actual_firmware_inventory = self.upd_serv.firmware_inventory
|
||||
# | THEN |
|
||||
self.assertIsInstance(actual_firmware_inventory,
|
||||
softwareinventory.SoftwareInventoryCollection)
|
||||
self.conn.get.return_value.json.assert_called_once_with()
|
||||
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
# | WHEN & THEN |
|
||||
self.assertIs(actual_firmware_inventory,
|
||||
self.upd_serv.firmware_inventory)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
|
@ -27,6 +27,7 @@ from sushy.resources.registry import message_registry_file
|
|||
from sushy.resources.sessionservice import session
|
||||
from sushy.resources.sessionservice import sessionservice
|
||||
from sushy.resources.system import system
|
||||
from sushy.resources.updateservice import updateservice
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
|
@ -143,6 +144,13 @@ class MainTestCase(base.TestCase):
|
|||
self.root._conn, 'asdf',
|
||||
redfish_version=self.root.redfish_version)
|
||||
|
||||
@mock.patch.object(updateservice, 'UpdateService', autospec=True)
|
||||
def test_get_update_service(self, mock_upd_serv):
|
||||
self.root.get_update_service()
|
||||
mock_upd_serv.assert_called_once_with(
|
||||
self.root._conn, '/redfish/v1/UpdateService',
|
||||
redfish_version=self.root.redfish_version)
|
||||
|
||||
@mock.patch.object(message_registry_file,
|
||||
'MessageRegistryFileCollection',
|
||||
autospec=True)
|
||||
|
@ -185,5 +193,10 @@ class BareMinimumMainTestCase(base.TestCase):
|
|||
exceptions.MissingAttributeError,
|
||||
'SessionService/@odata.id', self.root.get_session_service)
|
||||
|
||||
def test_get_update_service_when_updateservice_attr_absent(self):
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError,
|
||||
'UpdateService/@odata.id', self.root.get_update_service)
|
||||
|
||||
def test__get_registry_collection_when_registries_attr_absent(self):
|
||||
self.assertIsNone(self.root._get_registry_collection())
|
||||
|
|
Loading…
Reference in New Issue