Adds steps 'apply_configuration' and 'flash_firmware_sum'
Following inband deploy steps are added: 1. 'apply_configuration' is added for 'raid' interface. 2. 'flash_firmware_sum' is added for 'management' interface. Change-Id: I42e153aaa52befb13d0471a2a1f0a2401684aaea
This commit is contained in:
parent
6e03a55374
commit
5dc26eb950
@ -15,8 +15,48 @@
|
|||||||
from ironic_python_agent import hardware
|
from ironic_python_agent import hardware
|
||||||
|
|
||||||
from proliantutils.hpssa import manager as hpssa_manager
|
from proliantutils.hpssa import manager as hpssa_manager
|
||||||
|
from proliantutils import log
|
||||||
from proliantutils.sum import sum_controller
|
from proliantutils.sum import sum_controller
|
||||||
|
|
||||||
|
LOG = log.get_logger(__name__)
|
||||||
|
|
||||||
|
_RAID_APPLY_CONFIGURATION_ARGSINFO = {
|
||||||
|
"raid_config": {
|
||||||
|
"description": "The RAID configuration to apply.",
|
||||||
|
"required": True,
|
||||||
|
},
|
||||||
|
"delete_existing": {
|
||||||
|
"description": (
|
||||||
|
"Setting this to 'True' indicates to delete existing RAID "
|
||||||
|
"configuration prior to creating the new configuration. "
|
||||||
|
"Default value is 'True'."
|
||||||
|
),
|
||||||
|
"required": False,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_FIRMWARE_UPDATE_SUM_ARGSINFO = {
|
||||||
|
'url': {
|
||||||
|
'description': (
|
||||||
|
"The image location for SPP (Service Pack for Proliant) ISO."
|
||||||
|
),
|
||||||
|
'required': True,
|
||||||
|
},
|
||||||
|
'checksum': {
|
||||||
|
'description': (
|
||||||
|
"The md5 checksum of the SPP image file."
|
||||||
|
),
|
||||||
|
'required': True,
|
||||||
|
},
|
||||||
|
'components': {
|
||||||
|
'description': (
|
||||||
|
"The list of firmware component filenames. If not specified, "
|
||||||
|
"SUM updates all the firmware components."
|
||||||
|
),
|
||||||
|
'required': False,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ProliantHardwareManager(hardware.GenericHardwareManager):
|
class ProliantHardwareManager(hardware.GenericHardwareManager):
|
||||||
|
|
||||||
@ -36,22 +76,96 @@ class ProliantHardwareManager(hardware.GenericHardwareManager):
|
|||||||
:returns: A list of dictionaries, each item containing the step name,
|
:returns: A list of dictionaries, each item containing the step name,
|
||||||
interface and priority for the clean step.
|
interface and priority for the clean step.
|
||||||
"""
|
"""
|
||||||
return [{'step': 'create_configuration',
|
return [
|
||||||
'interface': 'raid',
|
{
|
||||||
'priority': 0},
|
'step': 'create_configuration',
|
||||||
{'step': 'delete_configuration',
|
'interface': 'raid',
|
||||||
'interface': 'raid',
|
'priority': 0,
|
||||||
'priority': 0},
|
'reboot_requested': False,
|
||||||
{'step': 'erase_devices',
|
},
|
||||||
'interface': 'deploy',
|
{
|
||||||
'priority': 0},
|
'step': 'delete_configuration',
|
||||||
{'step': 'update_firmware_sum',
|
'interface': 'raid',
|
||||||
'interface': 'management',
|
'priority': 0,
|
||||||
'priority': 0}]
|
'reboot_requested': False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'step': 'erase_devices',
|
||||||
|
'interface': 'deploy',
|
||||||
|
'priority': 0,
|
||||||
|
'reboot_requested': False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'step': 'update_firmware_sum',
|
||||||
|
'interface': 'management',
|
||||||
|
'priority': 0,
|
||||||
|
'reboot_requested': False,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_deploy_steps(self, node, ports):
|
||||||
|
"""Return the deploy steps supported by this hardware manager.
|
||||||
|
|
||||||
|
This method returns the deploy steps that are supported by
|
||||||
|
proliant hardware manager. This method is invoked on every
|
||||||
|
hardware manager by Ironic Python Agent to give this information
|
||||||
|
back to Ironic.
|
||||||
|
|
||||||
|
:param node: A dictionary of the node object
|
||||||
|
:param ports: A list of dictionaries containing information of ports
|
||||||
|
for the node
|
||||||
|
:returns: A list of dictionaries, each item containing the step name,
|
||||||
|
interface, priority, reboot_requested and
|
||||||
|
argsinfo for the deploy step.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'step': 'apply_configuration',
|
||||||
|
'interface': 'raid',
|
||||||
|
'priority': 0,
|
||||||
|
'reboot_requested': False,
|
||||||
|
'argsinfo': _RAID_APPLY_CONFIGURATION_ARGSINFO,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'step': 'flash_firmware_sum',
|
||||||
|
'interface': 'management',
|
||||||
|
'priority': 0,
|
||||||
|
'reboot_requested': False,
|
||||||
|
'argsinfo': _FIRMWARE_UPDATE_SUM_ARGSINFO,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
def evaluate_hardware_support(cls):
|
def evaluate_hardware_support(cls):
|
||||||
return hardware.HardwareSupport.SERVICE_PROVIDER
|
return hardware.HardwareSupport.SERVICE_PROVIDER
|
||||||
|
|
||||||
|
def apply_configuration(self, node, ports, raid_config,
|
||||||
|
delete_existing=True):
|
||||||
|
"""Apply RAID configuration.
|
||||||
|
|
||||||
|
:param node: A dictionary of the node object.
|
||||||
|
:param ports: A list of dictionaries containing information
|
||||||
|
of ports for the node.
|
||||||
|
:param raid_config: The configuration to apply.
|
||||||
|
:param delete_existing: Whether to delete the existing configuration.
|
||||||
|
:returns: The current RAID configuration of the below format.
|
||||||
|
raid_config = {
|
||||||
|
'logical_disks': [{
|
||||||
|
'size_gb': 100,
|
||||||
|
'raid_level': 1,
|
||||||
|
'physical_disks': [
|
||||||
|
'5I:0:1',
|
||||||
|
'5I:0:2'],
|
||||||
|
'controller': 'Smart array controller'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
if delete_existing:
|
||||||
|
self.delete_configuration(node, ports)
|
||||||
|
LOG.debug("Creating raid with configuration %(raid_config)s",
|
||||||
|
{'raid_config': raid_config})
|
||||||
|
return hpssa_manager.create_configuration(raid_config=raid_config)
|
||||||
|
|
||||||
def create_configuration(self, node, ports):
|
def create_configuration(self, node, ports):
|
||||||
"""Create RAID configuration on the bare metal.
|
"""Create RAID configuration on the bare metal.
|
||||||
|
|
||||||
@ -75,6 +189,12 @@ class ProliantHardwareManager(hardware.GenericHardwareManager):
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
target_raid_config = node.get('target_raid_config', {}).copy()
|
target_raid_config = node.get('target_raid_config', {}).copy()
|
||||||
|
if not target_raid_config:
|
||||||
|
LOG.debug("No target_raid_config found")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
LOG.debug("Creating raid with configuration %(raid_config)s",
|
||||||
|
{'raid_config': target_raid_config})
|
||||||
return hpssa_manager.create_configuration(
|
return hpssa_manager.create_configuration(
|
||||||
raid_config=target_raid_config)
|
raid_config=target_raid_config)
|
||||||
|
|
||||||
@ -114,10 +234,40 @@ class ProliantHardwareManager(hardware.GenericHardwareManager):
|
|||||||
|
|
||||||
This method performs firmware update on all or some of the firmware
|
This method performs firmware update on all or some of the firmware
|
||||||
components on the bare metal node.
|
components on the bare metal node.
|
||||||
|
:param node: A dictionary of the node object.
|
||||||
|
:param port: A list of dictionaries containing information of ports
|
||||||
|
for the node.
|
||||||
:returns: A string with return code and the statistics of
|
:returns: A string with return code and the statistics of
|
||||||
updated/failed components.
|
updated/failed components.
|
||||||
:raises: SUMOperationError, when the SUM based firmware update
|
:raises: SUMOperationError, when the SUM based firmware update
|
||||||
operation on the node fails.
|
operation on the node fails.
|
||||||
"""
|
"""
|
||||||
return sum_controller.update_firmware(node)
|
url = node['clean_step']['args'].get('url')
|
||||||
|
checksum = node['clean_step']['args'].get('checksum')
|
||||||
|
components = node['clean_step']['args'].get('components')
|
||||||
|
return sum_controller.update_firmware(node, url, checksum,
|
||||||
|
components=components)
|
||||||
|
|
||||||
|
def flash_firmware_sum(self, node, port, url,
|
||||||
|
checksum, components=None):
|
||||||
|
"""Performs SUM based firmware update on the bare metal node.
|
||||||
|
|
||||||
|
This method performs firmware update on all or some of the firmware
|
||||||
|
components on the bare metal node.
|
||||||
|
:param node: A dictionary of the node object.
|
||||||
|
:param port: A list of dictionaries containing information of ports
|
||||||
|
for the node.
|
||||||
|
:param url: URL of SPP (Service Pack for Proliant) ISO.
|
||||||
|
:param checksum: MD5 checksum of SPP ISO to verify the image.
|
||||||
|
:param components: List of filenames of the firmware components to be
|
||||||
|
flashed. If not provided, the firmware update is performed on all
|
||||||
|
the firmware components.
|
||||||
|
:returns: A string with return code and the statistics of
|
||||||
|
updated/failed components.
|
||||||
|
:raises: SUMOperationError, when the SUM based firmware update
|
||||||
|
operation on the node fails.
|
||||||
|
"""
|
||||||
|
LOG.debug("Flashing firmware from %(url)s for components %(comp)s",
|
||||||
|
{'url': url, 'comp': components})
|
||||||
|
return sum_controller.update_firmware(node, url, checksum,
|
||||||
|
components=components)
|
||||||
|
@ -155,25 +155,28 @@ def _parse_sum_ouput(exit_code):
|
|||||||
return "UPDATE STATUS: UNKNOWN"
|
return "UPDATE STATUS: UNKNOWN"
|
||||||
|
|
||||||
|
|
||||||
def update_firmware(node):
|
def update_firmware(node, url, checksum, components=None):
|
||||||
"""Performs SUM based firmware update on the node.
|
"""Performs SUM based firmware update on the node.
|
||||||
|
|
||||||
This method performs SUM firmware update by mounting the
|
This method performs SUM firmware update by mounting the
|
||||||
SPP ISO on the node. It performs firmware update on all or
|
SPP ISO on the node. It performs firmware update on all or
|
||||||
some of the firmware components.
|
some of the firmware components.
|
||||||
|
|
||||||
:param node: A node object of type dict.
|
:param node: A dictionary of the node object.
|
||||||
|
:param url: URL of SPP (Service Pack for Proliant) ISO.
|
||||||
|
:param checksum: MD5 checksum of SPP ISO to verify the image.
|
||||||
|
:param components: List of filenames of the firmware components to be
|
||||||
|
flashed. If not provided, the firmware update is performed on all
|
||||||
|
the firmware components.
|
||||||
:returns: Operation Status string.
|
:returns: Operation Status string.
|
||||||
:raises: SUMOperationError, when the vmedia device is not found or
|
:raises: SUMOperationError, when the vmedia device is not found or
|
||||||
when the mount operation fails or when the image validation fails.
|
when the mount operation fails or when the image validation fails.
|
||||||
:raises: IloConnectionError, when the iLO connection fails.
|
:raises: IloConnectionError, when the iLO connection fails.
|
||||||
:raises: IloError, when vmedia eject or insert operation fails.
|
:raises: IloError, when vmedia eject or insert operation fails.
|
||||||
"""
|
"""
|
||||||
sum_update_iso = node['clean_step']['args'].get('url')
|
|
||||||
|
|
||||||
# Validates the http image reference for SUM update ISO.
|
# Validates the http image reference for SUM update ISO.
|
||||||
try:
|
try:
|
||||||
utils.validate_href(sum_update_iso)
|
utils.validate_href(url)
|
||||||
except exception.ImageRefValidationFailed as e:
|
except exception.ImageRefValidationFailed as e:
|
||||||
raise exception.SUMOperationError(reason=e)
|
raise exception.SUMOperationError(reason=e)
|
||||||
|
|
||||||
@ -181,9 +184,9 @@ def update_firmware(node):
|
|||||||
# is identified by matching its label.
|
# is identified by matching its label.
|
||||||
time.sleep(WAIT_TIME_DISK_LABEL_TO_BE_VISIBLE)
|
time.sleep(WAIT_TIME_DISK_LABEL_TO_BE_VISIBLE)
|
||||||
vmedia_device_dir = "/dev/disk/by-label/"
|
vmedia_device_dir = "/dev/disk/by-label/"
|
||||||
for file in os.listdir(vmedia_device_dir):
|
for fname in os.listdir(vmedia_device_dir):
|
||||||
if fnmatch.fnmatch(file, 'SPP*'):
|
if fnmatch.fnmatch(fname, 'SPP*'):
|
||||||
vmedia_device_file = os.path.join(vmedia_device_dir, file)
|
vmedia_device_file = os.path.join(vmedia_device_dir, fname)
|
||||||
|
|
||||||
if not os.path.exists(vmedia_device_file):
|
if not os.path.exists(vmedia_device_file):
|
||||||
msg = "Unable to find the virtual media device for SUM"
|
msg = "Unable to find the virtual media device for SUM"
|
||||||
@ -191,9 +194,8 @@ def update_firmware(node):
|
|||||||
|
|
||||||
# Validates the SPP ISO image for any file corruption using the checksum
|
# Validates the SPP ISO image for any file corruption using the checksum
|
||||||
# of the ISO file.
|
# of the ISO file.
|
||||||
expected_checksum = node['clean_step']['args'].get('checksum')
|
|
||||||
try:
|
try:
|
||||||
utils.verify_image_checksum(vmedia_device_file, expected_checksum)
|
utils.verify_image_checksum(vmedia_device_file, checksum)
|
||||||
except exception.ImageRefValidationFailed as e:
|
except exception.ImageRefValidationFailed as e:
|
||||||
raise exception.SUMOperationError(reason=e)
|
raise exception.SUMOperationError(reason=e)
|
||||||
|
|
||||||
@ -215,7 +217,6 @@ def update_firmware(node):
|
|||||||
if not os.path.exists(sum_file_path):
|
if not os.path.exists(sum_file_path):
|
||||||
sum_file_path = os.path.join(vmedia_mount_point, HPSUM_LOCATION)
|
sum_file_path = os.path.join(vmedia_mount_point, HPSUM_LOCATION)
|
||||||
|
|
||||||
components = node['clean_step']['args'].get('components')
|
|
||||||
result = _execute_sum(sum_file_path, vmedia_mount_point,
|
result = _execute_sum(sum_file_path, vmedia_mount_point,
|
||||||
components=components)
|
components=components)
|
||||||
|
|
||||||
|
@ -28,24 +28,54 @@ class ProliantHardwareManagerTestCase(testtools.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.hardware_manager = hardware_manager.ProliantHardwareManager()
|
self.hardware_manager = hardware_manager.ProliantHardwareManager()
|
||||||
|
self.info = {'ilo_address': '1.2.3.4',
|
||||||
|
'ilo_password': '12345678',
|
||||||
|
'ilo_username': 'admin'}
|
||||||
|
clean_step = {
|
||||||
|
'interface': 'management',
|
||||||
|
'step': 'update_firmware_sum',
|
||||||
|
'args': {'url': 'http://1.2.3.4/SPP.iso',
|
||||||
|
'checksum': '1234567890'}}
|
||||||
|
self.node = {'driver_info': self.info,
|
||||||
|
'clean_step': clean_step}
|
||||||
super(ProliantHardwareManagerTestCase, self).setUp()
|
super(ProliantHardwareManagerTestCase, self).setUp()
|
||||||
|
|
||||||
def test_get_clean_steps(self):
|
def test_get_clean_steps(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[{'step': 'create_configuration',
|
[{'step': 'create_configuration',
|
||||||
'interface': 'raid',
|
'interface': 'raid',
|
||||||
'priority': 0},
|
'priority': 0,
|
||||||
|
'reboot_requested': False},
|
||||||
{'step': 'delete_configuration',
|
{'step': 'delete_configuration',
|
||||||
'interface': 'raid',
|
'interface': 'raid',
|
||||||
'priority': 0},
|
'priority': 0,
|
||||||
|
'reboot_requested': False},
|
||||||
{'step': 'erase_devices',
|
{'step': 'erase_devices',
|
||||||
'interface': 'deploy',
|
'interface': 'deploy',
|
||||||
'priority': 0},
|
'priority': 0,
|
||||||
|
'reboot_requested': False},
|
||||||
{'step': 'update_firmware_sum',
|
{'step': 'update_firmware_sum',
|
||||||
'interface': 'management',
|
'interface': 'management',
|
||||||
'priority': 0}],
|
'priority': 0,
|
||||||
|
'reboot_requested': False}],
|
||||||
self.hardware_manager.get_clean_steps("", ""))
|
self.hardware_manager.get_clean_steps("", ""))
|
||||||
|
|
||||||
|
def test_get_deploy_steps(self):
|
||||||
|
self.assertEqual(
|
||||||
|
[{'step': 'apply_configuration',
|
||||||
|
'interface': 'raid',
|
||||||
|
'reboot_requested': False,
|
||||||
|
'priority': 0,
|
||||||
|
'argsinfo': (
|
||||||
|
hardware_manager._RAID_APPLY_CONFIGURATION_ARGSINFO)},
|
||||||
|
{'step': 'flash_firmware_sum',
|
||||||
|
'interface': 'management',
|
||||||
|
'reboot_requested': False,
|
||||||
|
'priority': 0,
|
||||||
|
'argsinfo': (
|
||||||
|
hardware_manager._FIRMWARE_UPDATE_SUM_ARGSINFO)}],
|
||||||
|
self.hardware_manager.get_deploy_steps("", []))
|
||||||
|
|
||||||
@mock.patch.object(hpssa_manager, 'create_configuration')
|
@mock.patch.object(hpssa_manager, 'create_configuration')
|
||||||
def test_create_configuration(self, create_mock):
|
def test_create_configuration(self, create_mock):
|
||||||
create_mock.return_value = 'current-config'
|
create_mock.return_value = 'current-config'
|
||||||
@ -55,6 +85,40 @@ class ProliantHardwareManagerTestCase(testtools.TestCase):
|
|||||||
create_mock.assert_called_once_with(raid_config={'foo': 'bar'})
|
create_mock.assert_called_once_with(raid_config={'foo': 'bar'})
|
||||||
self.assertEqual('current-config', ret)
|
self.assertEqual('current-config', ret)
|
||||||
|
|
||||||
|
@mock.patch.object(hpssa_manager, 'create_configuration')
|
||||||
|
def test_create_configuration_no_target_config(self, create_mock):
|
||||||
|
create_mock.return_value = 'current-config'
|
||||||
|
manager = self.hardware_manager
|
||||||
|
node = {'target_raid_config': {}}
|
||||||
|
manager.create_configuration(node, [])
|
||||||
|
create_mock.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch.object(hardware_manager.ProliantHardwareManager,
|
||||||
|
'delete_configuration')
|
||||||
|
@mock.patch.object(hpssa_manager, 'create_configuration')
|
||||||
|
def test_apply_configuration_with_delete(self, create_mock, delete_mock):
|
||||||
|
create_mock.return_value = 'current-config'
|
||||||
|
manager = self.hardware_manager
|
||||||
|
raid_config = {'foo': 'bar'}
|
||||||
|
ret = manager.apply_configuration("", [], raid_config,
|
||||||
|
delete_existing=True)
|
||||||
|
delete_mock.assert_called_once_with("", [])
|
||||||
|
create_mock.assert_called_once_with(raid_config={'foo': 'bar'})
|
||||||
|
self.assertEqual('current-config', ret)
|
||||||
|
|
||||||
|
@mock.patch.object(hardware_manager.ProliantHardwareManager,
|
||||||
|
'delete_configuration')
|
||||||
|
@mock.patch.object(hpssa_manager, 'create_configuration')
|
||||||
|
def test_apply_configuration_no_delete(self, create_mock, delete_mock):
|
||||||
|
create_mock.return_value = 'current-config'
|
||||||
|
manager = self.hardware_manager
|
||||||
|
raid_config = {'foo': 'bar'}
|
||||||
|
ret = manager.apply_configuration("", [], raid_config,
|
||||||
|
delete_existing=False)
|
||||||
|
create_mock.assert_called_once_with(raid_config={'foo': 'bar'})
|
||||||
|
delete_mock.assert_not_called()
|
||||||
|
self.assertEqual('current-config', ret)
|
||||||
|
|
||||||
@mock.patch.object(hpssa_manager, 'delete_configuration')
|
@mock.patch.object(hpssa_manager, 'delete_configuration')
|
||||||
def test_delete_configuration(self, delete_mock):
|
def test_delete_configuration(self, delete_mock):
|
||||||
delete_mock.return_value = 'current-config'
|
delete_mock.return_value = 'current-config'
|
||||||
@ -96,7 +160,22 @@ class ProliantHardwareManagerTestCase(testtools.TestCase):
|
|||||||
@mock.patch.object(sum_controller, 'update_firmware')
|
@mock.patch.object(sum_controller, 'update_firmware')
|
||||||
def test_update_firmware_sum(self, update_mock):
|
def test_update_firmware_sum(self, update_mock):
|
||||||
update_mock.return_value = "log files"
|
update_mock.return_value = "log files"
|
||||||
node = {'foo': 'bar'}
|
url = self.node['clean_step']['args'].get('url')
|
||||||
ret = self.hardware_manager.update_firmware_sum(node, "")
|
csum = self.node['clean_step']['args'].get('checksum')
|
||||||
update_mock.assert_called_once_with(node)
|
comp = self.node['clean_step']['args'].get('components')
|
||||||
|
ret = self.hardware_manager.update_firmware_sum(self.node, "")
|
||||||
|
update_mock.assert_called_once_with(self.node, url, csum,
|
||||||
|
components=comp)
|
||||||
|
self.assertEqual('log files', ret)
|
||||||
|
|
||||||
|
@mock.patch.object(sum_controller, 'update_firmware')
|
||||||
|
def test_flash_firmware_sum(self, update_mock):
|
||||||
|
update_mock.return_value = "log files"
|
||||||
|
url = self.node['clean_step']['args'].get('url')
|
||||||
|
csum = self.node['clean_step']['args'].get('checksum')
|
||||||
|
comp = self.node['clean_step']['args'].get('components')
|
||||||
|
ret = self.hardware_manager.flash_firmware_sum(self.node, "", url,
|
||||||
|
csum, components=comp)
|
||||||
|
update_mock.assert_called_once_with(self.node, url, csum,
|
||||||
|
components=comp)
|
||||||
self.assertEqual('log files', ret)
|
self.assertEqual('log files', ret)
|
||||||
|
@ -16,6 +16,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import tarfile
|
import tarfile
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import time
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
@ -152,6 +153,7 @@ class SUMFirmwareUpdateTest(testtools.TestCase):
|
|||||||
os.remove(file_object.name)
|
os.remove(file_object.name)
|
||||||
os.remove(tar_file.name)
|
os.remove(tar_file.name)
|
||||||
|
|
||||||
|
@mock.patch.object(time, 'sleep')
|
||||||
@mock.patch.object(utils, 'validate_href')
|
@mock.patch.object(utils, 'validate_href')
|
||||||
@mock.patch.object(utils, 'verify_image_checksum')
|
@mock.patch.object(utils, 'verify_image_checksum')
|
||||||
@mock.patch.object(sum_controller, '_execute_sum')
|
@mock.patch.object(sum_controller, '_execute_sum')
|
||||||
@ -164,21 +166,23 @@ class SUMFirmwareUpdateTest(testtools.TestCase):
|
|||||||
def test_update_firmware(self, execute_mock, mkdir_mock,
|
def test_update_firmware(self, execute_mock, mkdir_mock,
|
||||||
exists_mock, mkdtemp_mock, rmtree_mock,
|
exists_mock, mkdtemp_mock, rmtree_mock,
|
||||||
listdir_mock, execute_sum_mock,
|
listdir_mock, execute_sum_mock,
|
||||||
verify_image_mock, validate_mock):
|
verify_image_mock, validate_mock, sleep_mock):
|
||||||
execute_sum_mock.return_value = 'SUCCESS'
|
execute_sum_mock.return_value = 'SUCCESS'
|
||||||
listdir_mock.return_value = ['SPP_LABEL']
|
listdir_mock.return_value = ['SPP_LABEL']
|
||||||
mkdtemp_mock.return_value = "/tempdir"
|
mkdtemp_mock.return_value = "/tempdir"
|
||||||
null_output = ["", ""]
|
null_output = ["", ""]
|
||||||
exists_mock.side_effect = [True, False]
|
exists_mock.side_effect = [True, False]
|
||||||
execute_mock.side_effect = [null_output, null_output]
|
execute_mock.side_effect = [null_output, null_output]
|
||||||
|
url = "http://a.b.c.d/spp.iso"
|
||||||
ret_val = sum_controller.update_firmware(self.node)
|
checksum = "12345678"
|
||||||
|
components = ['abc', 'pqr']
|
||||||
|
ret_val = sum_controller.update_firmware(self.node, url, checksum,
|
||||||
|
components)
|
||||||
|
|
||||||
execute_mock.assert_any_call('mount', "/dev/disk/by-label/SPP_LABEL",
|
execute_mock.assert_any_call('mount', "/dev/disk/by-label/SPP_LABEL",
|
||||||
"/tempdir")
|
"/tempdir")
|
||||||
execute_sum_mock.assert_any_call('/tempdir/hp/swpackages/hpsum',
|
execute_sum_mock.assert_any_call('/tempdir/hp/swpackages/hpsum',
|
||||||
'/tempdir',
|
'/tempdir', components=components)
|
||||||
components=None)
|
|
||||||
calls = [mock.call("/dev/disk/by-label/SPP_LABEL"),
|
calls = [mock.call("/dev/disk/by-label/SPP_LABEL"),
|
||||||
mock.call("/tempdir/packages/smartupdate")]
|
mock.call("/tempdir/packages/smartupdate")]
|
||||||
exists_mock.assert_has_calls(calls, any_order=False)
|
exists_mock.assert_has_calls(calls, any_order=False)
|
||||||
@ -187,6 +191,7 @@ class SUMFirmwareUpdateTest(testtools.TestCase):
|
|||||||
rmtree_mock.assert_called_once_with("/tempdir", ignore_errors=True)
|
rmtree_mock.assert_called_once_with("/tempdir", ignore_errors=True)
|
||||||
self.assertEqual('SUCCESS', ret_val)
|
self.assertEqual('SUCCESS', ret_val)
|
||||||
|
|
||||||
|
@mock.patch.object(time, 'sleep')
|
||||||
@mock.patch.object(utils, 'validate_href')
|
@mock.patch.object(utils, 'validate_href')
|
||||||
@mock.patch.object(utils, 'verify_image_checksum')
|
@mock.patch.object(utils, 'verify_image_checksum')
|
||||||
@mock.patch.object(sum_controller, '_execute_sum')
|
@mock.patch.object(sum_controller, '_execute_sum')
|
||||||
@ -199,17 +204,22 @@ class SUMFirmwareUpdateTest(testtools.TestCase):
|
|||||||
def test_update_firmware_sum(self, execute_mock, mkdir_mock,
|
def test_update_firmware_sum(self, execute_mock, mkdir_mock,
|
||||||
exists_mock, mkdtemp_mock, rmtree_mock,
|
exists_mock, mkdtemp_mock, rmtree_mock,
|
||||||
listdir_mock, execute_sum_mock,
|
listdir_mock, execute_sum_mock,
|
||||||
verify_image_mock, validate_mock):
|
verify_image_mock, validate_mock, sleep_mock):
|
||||||
execute_sum_mock.return_value = 'SUCCESS'
|
execute_sum_mock.return_value = 'SUCCESS'
|
||||||
listdir_mock.return_value = ['SPP_LABEL']
|
listdir_mock.return_value = ['SPP_LABEL']
|
||||||
mkdtemp_mock.return_value = "/tempdir"
|
mkdtemp_mock.return_value = "/tempdir"
|
||||||
null_output = ["", ""]
|
null_output = ["", ""]
|
||||||
exists_mock.side_effect = [True, True]
|
exists_mock.side_effect = [True, True, True, True]
|
||||||
execute_mock.side_effect = [null_output, null_output]
|
execute_mock.side_effect = [null_output, null_output,
|
||||||
|
null_output, null_output]
|
||||||
|
url = "http://a.b.c.d/spp.iso"
|
||||||
|
checksum = "12345678"
|
||||||
|
|
||||||
ret_val = sum_controller.update_firmware(self.node)
|
ret_val = sum_controller.update_firmware(
|
||||||
|
self.node, url, checksum)
|
||||||
|
|
||||||
execute_mock.assert_any_call('mount', "/dev/disk/by-label/SPP_LABEL",
|
execute_mock.assert_any_call('mount',
|
||||||
|
"/dev/disk/by-label/SPP_LABEL",
|
||||||
"/tempdir")
|
"/tempdir")
|
||||||
execute_sum_mock.assert_any_call('/tempdir/packages/smartupdate',
|
execute_sum_mock.assert_any_call('/tempdir/packages/smartupdate',
|
||||||
'/tempdir',
|
'/tempdir',
|
||||||
@ -226,41 +236,54 @@ class SUMFirmwareUpdateTest(testtools.TestCase):
|
|||||||
def test_update_firmware_throws_for_nonexistent_file(self,
|
def test_update_firmware_throws_for_nonexistent_file(self,
|
||||||
validate_href_mock):
|
validate_href_mock):
|
||||||
invalid_file_path = '/some/invalid/file/path'
|
invalid_file_path = '/some/invalid/file/path'
|
||||||
|
url = "http://a.b.c.d/spp.iso"
|
||||||
|
checksum = "12345678"
|
||||||
|
components = ['abc', 'pqr']
|
||||||
value = ("Got HTTP code 503 instead of 200 in response to "
|
value = ("Got HTTP code 503 instead of 200 in response to "
|
||||||
"HEAD request.")
|
"HEAD request.")
|
||||||
validate_href_mock.side_effect = exception.ImageRefValidationFailed(
|
validate_href_mock.side_effect = exception.ImageRefValidationFailed(
|
||||||
reason=value, image_href=invalid_file_path)
|
reason=value, image_href=invalid_file_path)
|
||||||
|
|
||||||
exc = self.assertRaises(exception.SUMOperationError,
|
exc = self.assertRaises(exception.SUMOperationError,
|
||||||
sum_controller.update_firmware, self.node)
|
sum_controller.update_firmware, self.node,
|
||||||
|
url, checksum, components)
|
||||||
self.assertIn(value, str(exc))
|
self.assertIn(value, str(exc))
|
||||||
|
|
||||||
|
@mock.patch.object(time, 'sleep')
|
||||||
@mock.patch.object(utils, 'validate_href')
|
@mock.patch.object(utils, 'validate_href')
|
||||||
@mock.patch.object(os.path, 'exists')
|
@mock.patch.object(os.path, 'exists')
|
||||||
@mock.patch.object(os, 'listdir')
|
@mock.patch.object(os, 'listdir')
|
||||||
def test_update_firmware_device_file_not_found(self,
|
def test_update_firmware_device_file_not_found(self,
|
||||||
listdir_mock, exists_mock,
|
listdir_mock, exists_mock,
|
||||||
validate_mock):
|
validate_mock, sleep_mock):
|
||||||
listdir_mock.return_value = ['SPP_LABEL']
|
listdir_mock.return_value = ['SPP_LABEL']
|
||||||
exists_mock.return_value = False
|
exists_mock.return_value = False
|
||||||
|
url = "http://a.b.c.d/spp.iso"
|
||||||
|
checksum = "12345678"
|
||||||
|
components = ['abc', 'pqr']
|
||||||
|
|
||||||
msg = ("An error occurred while performing SUM based firmware "
|
msg = ("An error occurred while performing SUM based firmware "
|
||||||
"update, reason: Unable to find the virtual media device "
|
"update, reason: Unable to find the virtual media device "
|
||||||
"for SUM")
|
"for SUM")
|
||||||
exc = self.assertRaises(exception.SUMOperationError,
|
exc = self.assertRaises(exception.SUMOperationError,
|
||||||
sum_controller.update_firmware, self.node)
|
sum_controller.update_firmware, self.node,
|
||||||
|
url, checksum, components=components)
|
||||||
self.assertEqual(msg, str(exc))
|
self.assertEqual(msg, str(exc))
|
||||||
exists_mock.assert_called_once_with("/dev/disk/by-label/SPP_LABEL")
|
exists_mock.assert_called_once_with("/dev/disk/by-label/SPP_LABEL")
|
||||||
|
|
||||||
|
@mock.patch.object(time, 'sleep')
|
||||||
@mock.patch.object(utils, 'validate_href')
|
@mock.patch.object(utils, 'validate_href')
|
||||||
@mock.patch.object(utils, 'verify_image_checksum')
|
@mock.patch.object(utils, 'verify_image_checksum')
|
||||||
@mock.patch.object(os, 'listdir')
|
@mock.patch.object(os, 'listdir')
|
||||||
@mock.patch.object(os.path, 'exists')
|
@mock.patch.object(os.path, 'exists')
|
||||||
def test_update_firmware_invalid_checksum(self, exists_mock,
|
def test_update_firmware_invalid_checksum(self, exists_mock,
|
||||||
listdir_mock, verify_image_mock,
|
listdir_mock, verify_image_mock,
|
||||||
validate_mock):
|
validate_mock, sleep_mock):
|
||||||
listdir_mock.return_value = ['SPP_LABEL']
|
listdir_mock.return_value = ['SPP_LABEL']
|
||||||
exists_mock.side_effect = [True, False]
|
exists_mock.side_effect = [True, False]
|
||||||
|
url = "http://1.2.3.4/SPP.iso"
|
||||||
|
checksum = "1234567890"
|
||||||
|
components = ['abc', 'pqr']
|
||||||
|
|
||||||
value = ("Error verifying image checksum. Image "
|
value = ("Error verifying image checksum. Image "
|
||||||
"http://1.2.3.4/SPP.iso failed to verify against checksum "
|
"http://1.2.3.4/SPP.iso failed to verify against checksum "
|
||||||
@ -270,12 +293,14 @@ class SUMFirmwareUpdateTest(testtools.TestCase):
|
|||||||
reason=value, image_href='http://1.2.3.4/SPP.iso')
|
reason=value, image_href='http://1.2.3.4/SPP.iso')
|
||||||
|
|
||||||
self.assertRaisesRegex(exception.SUMOperationError, value,
|
self.assertRaisesRegex(exception.SUMOperationError, value,
|
||||||
sum_controller.update_firmware, self.node)
|
sum_controller.update_firmware, self.node,
|
||||||
|
url, checksum, components=components)
|
||||||
|
|
||||||
verify_image_mock.assert_called_once_with(
|
verify_image_mock.assert_called_once_with(
|
||||||
'/dev/disk/by-label/SPP_LABEL', '1234567890')
|
'/dev/disk/by-label/SPP_LABEL', '1234567890')
|
||||||
exists_mock.assert_called_once_with("/dev/disk/by-label/SPP_LABEL")
|
exists_mock.assert_called_once_with("/dev/disk/by-label/SPP_LABEL")
|
||||||
|
|
||||||
|
@mock.patch.object(time, 'sleep')
|
||||||
@mock.patch.object(utils, 'validate_href')
|
@mock.patch.object(utils, 'validate_href')
|
||||||
@mock.patch.object(utils, 'verify_image_checksum')
|
@mock.patch.object(utils, 'verify_image_checksum')
|
||||||
@mock.patch.object(processutils, 'execute')
|
@mock.patch.object(processutils, 'execute')
|
||||||
@ -286,16 +311,20 @@ class SUMFirmwareUpdateTest(testtools.TestCase):
|
|||||||
def test_update_firmware_mount_fails(self, listdir_mock,
|
def test_update_firmware_mount_fails(self, listdir_mock,
|
||||||
exists_mock, mkdir_mock,
|
exists_mock, mkdir_mock,
|
||||||
mkdtemp_mock, execute_mock,
|
mkdtemp_mock, execute_mock,
|
||||||
verify_image_mock, validate_mock):
|
verify_image_mock, validate_mock,
|
||||||
|
sleep_mock):
|
||||||
listdir_mock.return_value = ['SPP_LABEL']
|
listdir_mock.return_value = ['SPP_LABEL']
|
||||||
exists_mock.return_value = True
|
exists_mock.return_value = True
|
||||||
mkdtemp_mock.return_value = "/tempdir"
|
mkdtemp_mock.return_value = "/tempdir"
|
||||||
execute_mock.side_effect = processutils.ProcessExecutionError
|
execute_mock.side_effect = processutils.ProcessExecutionError
|
||||||
|
url = "http://a.b.c.d/spp.iso"
|
||||||
|
checksum = "12345678"
|
||||||
|
|
||||||
msg = ("Unable to mount virtual media device "
|
msg = ("Unable to mount virtual media device "
|
||||||
"/dev/disk/by-label/SPP_LABEL")
|
"/dev/disk/by-label/SPP_LABEL")
|
||||||
exc = self.assertRaises(exception.SUMOperationError,
|
exc = self.assertRaises(exception.SUMOperationError,
|
||||||
sum_controller.update_firmware, self.node)
|
sum_controller.update_firmware, self.node,
|
||||||
|
url, checksum)
|
||||||
self.assertIn(msg, str(exc))
|
self.assertIn(msg, str(exc))
|
||||||
exists_mock.assert_called_once_with("/dev/disk/by-label/SPP_LABEL")
|
exists_mock.assert_called_once_with("/dev/disk/by-label/SPP_LABEL")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user