RIS:Add get_pending_boot_mode

Add get_pending_boot_mode functionality to RIS.

Change-Id: I075b9eb5a7dc94bd8302cf0884271fdbb536b37d
This commit is contained in:
Anusha Ramineni
2015-03-26 21:18:13 +05:30
parent 91e1a4ff3d
commit 8146a5c40c
4 changed files with 352 additions and 58 deletions

View File

@@ -17,13 +17,22 @@ from proliantutils.ilo import operations
from proliantutils.ilo import ribcl
from proliantutils.ilo import ris
SUPPORTED_RIS_METHODS = ['get_product_name', 'get_http_boot_url',
'set_http_boot_url', 'get_host_power_status',
'get_current_boot_mode', 'set_pending_boot_mode',
'reset_ilo', 'reset_ilo_credential',
'reset_secure_keys', 'clear_secure_boot_keys',
'get_secure_boot_mode', 'set_secure_boot_mode',
'reset_bios_to_default']
SUPPORTED_RIS_METHODS = [
'clear_secure_boot_keys',
'get_current_boot_mode',
'get_host_power_status',
'get_http_boot_url',
'get_pending_boot_mode',
'get_product_name',
'get_secure_boot_mode',
'reset_bios_to_default',
'reset_ilo',
'reset_ilo_credential',
'reset_secure_boot_keys',
'set_http_boot_url',
'set_pending_boot_mode',
'set_secure_boot_mode'
]
class IloClient(operations.IloOperations):

View File

@@ -314,8 +314,8 @@ class RISOperations(operations.IloOperations):
for property in properties:
if property not in bios_settings:
# not supported on this platform
msg = ('\tBIOS Property "' + property + '" is not'
' supported on this system.')
msg = ('BIOS Property "' + property + '" is not'
' supported on this system.')
raise exception.IloCommandNotSupportedError(msg)
return headers, bios_uri, bios_settings
@@ -325,9 +325,30 @@ class RISOperations(operations.IloOperations):
' does not exist')
raise exception.IloCommandNotSupportedError(msg)
def _get_bios_settings_resource(self, data):
"""Get the BIOS settings resource."""
try:
bios_settings_uri = data['links']['Settings']['href']
except KeyError:
msg = ('BIOS Settings resource not found.')
raise exception.IloError(msg)
status, headers, bios_settings = self._rest_get(bios_settings_uri)
if status != 200:
msg = self._get_extended_error(bios_settings)
raise exception.IloError(msg)
return headers, bios_settings_uri, bios_settings
def _validate_if_patch_supported(self, headers, uri):
"""Check if the PATCH Operation is allowed on the resource."""
if not self._operation_allowed(headers, 'PATCH'):
msg = ('PATCH Operation not supported on the resource '
'"%s"' % uri)
raise exception.IloError(msg)
def _get_bios_setting(self, bios_property):
"""Retrieves bios settings of the server."""
headers, bios_uri, bios_settings = self._check_bios_resource([
bios_property])
return bios_settings[bios_property]
@@ -345,12 +366,12 @@ class RISOperations(operations.IloOperations):
"""Change the bios settings to specified values."""
keys = properties.keys()
# Check if the BIOS resource/property exists.
headers, bios_uri, bios_settings = self._check_bios_resource(keys)
# Get the BIOS Settings resource, if PATCH not supported on BIOS.
bios_uri = self._get_bios_settings_resource(headers, bios_uri,
bios_settings)
headers, bios_uri, settings = self._check_bios_resource(keys)
if not self._operation_allowed(headers, 'PATCH'):
headers, bios_uri, _ = self._get_bios_settings_resource(settings)
self._validate_if_patch_supported(headers, bios_uri)
request_headers = self._get_bios_hash_password(self.bios_password)
# perform the patch
status, headers, response = self._rest_patch(bios_uri, request_headers,
properties)
if status >= 300:
@@ -360,7 +381,6 @@ class RISOperations(operations.IloOperations):
def _change_secure_boot_settings(self, property, value):
"""Change secure boot settings on the server."""
system = self._get_host_details()
# find the BIOS URI
if ('links' not in system['Oem']['Hp'] or
'SecureBoot' not in system['Oem']['Hp']['links']):
@@ -402,30 +422,6 @@ class RISOperations(operations.IloOperations):
else:
return False
def _get_bios_settings_resource(self, headers, bios_uri, bios_settings):
"""Get the BIOS settings resource.
Check if the BIOS resource supports PATCH Operation. If not, get the
Settings resource which supports the PATCH Operation.
"""
if not self._operation_allowed(headers, 'PATCH'): # this is GET-only
# Get the settings for patch operation
try:
bios_uri = bios_settings['links']['Settings']['href']
except KeyError:
msg = ('BIOS Settings resource not found.')
raise Exception.IloError(msg)
status, headers, bios_settings = self._rest_get(bios_uri)
# this should allow PATCH, else raise error
if not self._operation_allowed(headers, 'PATCH'):
msg = ('PATCH Operation not supported on the resource'
'%s ' % bios_uri)
raise exception.IloError(msg)
return bios_uri
def get_product_name(self):
"""Gets the product name of the server.
@@ -510,7 +506,6 @@ class RISOperations(operations.IloOperations):
:raises: IloCommandNotSupportedInBiosError, if the system is
in the bios boot mode.
"""
if(self._validate_uefi_boot_mode() is True):
return self._get_bios_setting('UefiShellStartupUrl')
else:
@@ -525,7 +520,6 @@ class RISOperations(operations.IloOperations):
:raises: IloCommandNotSupportedInBiosError, if the system is
in the bios boot mode.
"""
if(self._validate_uefi_boot_mode() is True):
self._change_bios_setting({'UefiShellStartupUrl': url})
else:
@@ -544,22 +538,36 @@ class RISOperations(operations.IloOperations):
return boot_mode.upper()
def get_pending_boot_mode(self):
"""Retrieves the pending boot mode of the server.
Gets the boot mode to be set on next reset.
:returns: either LEGACY or UEFI.
:raises: IloError, on an error from iLO.
"""
headers, uri, bios_settings = self._check_bios_resource(['BootMode'])
_, _, settings = self._get_bios_settings_resource(bios_settings)
boot_mode = settings.get('BootMode')
if boot_mode == 'LegacyBios':
boot_mode = 'legacy'
return boot_mode.upper()
def set_pending_boot_mode(self, boot_mode):
"""Sets the boot mode of the system for next boot.
:param boot_mode: either 'uefi' or 'bios'.
:param boot_mode: either 'uefi' or 'legacy'.
:raises: IloInvalidInputError, on an invalid input.
:raises: IloError, on an error from iLO.
:raises: IloCommandNotSupportedError, if the command is not supported
on the server.
"""
if boot_mode not in ['uefi', 'bios']:
if boot_mode.lower() not in ['uefi', 'legacy']:
msg = 'Invalid Boot mode specified'
raise exception.IloInvalidInputError(msg)
boot_properties = {'BootMode': boot_mode}
if boot_mode == 'bios':
if boot_mode == 'legacy':
boot_properties['BootMode'] = 'LegacyBios'
else:
# If Boot Mode is 'Uefi' set the UEFIOptimizedBoot first.
@@ -642,13 +650,17 @@ class RISOperations(operations.IloOperations):
"Settings.")
raise exception.IloCommandNotSupportedError(msg)
# Check if BIOS resource supports patch, else get the settings
if not self._operation_allowed(headers_bios, 'PATCH'):
headers, bios_uri, _ = self._get_bios_settings_resource(
bios_settings)
self._validate_if_patch_supported(headers, bios_uri)
status, headers, config = self._rest_get(base_config_uri)
if status != 200:
msg = self._get_extended_error(config)
raise exception.IloError(msg)
# Check if BIOS resource supports patch, else get the settings
bios_uri = self._get_bios_settings_resource(headers_bios, bios_uri,
bios_settings)
new_bios_settings = {}
for cfg in config['BaseConfigs']:
default_settings = cfg.get('default', None)
@@ -659,7 +671,6 @@ class RISOperations(operations.IloOperations):
msg = ("Default Settings not found in 'BaseConfigs' resource.")
raise exception.IloCommandNotSupportedError(msg)
request_headers = self._get_bios_hash_password(self.bios_password)
# perform the patch
status, headers, response = self._rest_patch(bios_uri, request_headers,
new_bios_settings)
if status >= 300:

View File

@@ -738,3 +738,186 @@ GET_BIOS_SETTINGS = """
}
}
"""
GET_BASE_CONFIG = """
{
"BaseConfigs":
[
{
"default":
{
"AcpiRootBridgePxm": "Enabled",
"AcpiSlit": "Enabled",
"AdjSecPrefetch": "Enabled",
"AdminEmail": "",
"AdminName": "",
"AdminOtherInfo": "",
"AdminPassword": "",
"AdminPhone": "",
"AdvancedMemProtection": "AdvancedEcc",
"AsrStatus": "Enabled",
"AsrTimeoutMinutes": "10",
"AssetTagProtection": "Unlocked",
"AutoPowerOn": "RestoreLastState",
"BootMode": "Uefi",
"BootOrderPolicy": "RetryIndefinitely",
"ChannelInterleaving": "Enabled",
"CollabPowerControl": "Enabled",
"ConsistentDevNaming": "LomsOnly",
"CustomPostMessage": "",
"DcuIpPrefetcher": "Enabled",
"DcuStreamPrefetcher": "Enabled",
"Description": "BIOS System Defaults",
"Dhcpv4": "Enabled",
"DynamicPowerCapping": "Auto",
"DynamicPowerResponse": "Fast",
"EmbNicEnable": "Enabled",
"EmbSas1Boot": "AllTargets",
"EmbSata1Enable": "Enabled",
"EmbSata2Enable": "Enabled",
"EmbVideoConnection": "Auto",
"EmbeddedDiagnostics": "Enabled",
"EmbeddedDiagsMode": "Auto",
"EmbeddedSata": "Ahci",
"EmbeddedSerialPort": "Com1Irq4",
"EmbeddedUefiShell": "Enabled",
"EmbeddedUserPartition": "Disabled",
"EmsConsole": "Disabled",
"EnergyPerfBias": "BalancedPerf",
"EraseUserDefaults": "No",
"ExtendedAmbientTemp": "Disabled",
"ExtendedMemTest": "Disabled",
"F11BootMenu": "Enabled",
"FCScanPolicy": "AllTargets",
"FanFailPolicy": "Shutdown",
"FanInstallReq": "EnableMessaging",
"HwPrefetcher": "Enabled",
"IntelDmiLinkFreq": "Auto",
"IntelNicDmaChannels": "Enabled",
"IntelPerfMonitoring": "Disabled",
"IntelProcVtd": "Enabled",
"IntelQpiFreq": "Auto",
"IntelQpiLinkEn": "Auto",
"IntelQpiPowerManagement": "Enabled",
"IntelTxt": "Disabled",
"IntelligentProvisioning": "Enabled",
"InternalSDCardSlot": "Enabled",
"IoNonPostedPrefetching": "Enabled",
"Ipv4Address": "0.0.0.0",
"Ipv4Gateway": "0.0.0.0",
"Ipv4PrimaryDNS": "0.0.0.0",
"Ipv4SecondaryDNS": "0.0.0.0",
"Ipv4SubnetMask": "0.0.0.0",
"MaxMemBusFreqMHz": "Auto",
"MaxPcieSpeed": "MaxSupported",
"MemFastTraining": "Enabled",
"MinProcIdlePkgState": "C6Retention",
"MinProcIdlePower": "C6",
"MixedPowerSupplyReporting": "Enabled",
"NetworkBootRetry": "Enabled",
"NicBoot1": "NetworkBoot",
"NicBoot2": "Disabled",
"NicBoot3": "Disabled",
"NicBoot4": "Disabled",
"NmiDebugButton": "Enabled",
"NodeInterleaving": "Disabled",
"NumaGroupSizeOpt": "Clustered",
"OldAdminPassword": "",
"OldPowerOnPassword": "",
"PciBusPadding": "Enabled",
"PciSlot1Enable": "Enabled",
"PostF1Prompt": "Delayed20Sec",
"PowerButton": "Enabled",
"PowerOnDelay": "None",
"PowerOnLogo": "Enabled",
"PowerOnPassword": "",
"PowerProfile": "BalancedPowerPerf",
"PowerRegulator": "DynamicPowerSavings",
"PreBootNetwork": "Auto",
"ProcAes": "Enabled",
"ProcCoreDisable": 0,
"ProcNoExecute": "Enabled",
"ProcVirtualization": "Enabled",
"ProcX2Apic": "Enabled",
"QpiBandwidthOpt": "Balanced",
"QpiSnoopConfig": "Standard",
"RedundantPowerSupply": "BalancedMode",
"RemovableFlashBootSeq": "ExternalKeysFirst",
"RestoreDefaults": "No",
"RestoreManufacturingDefaults": "No",
"SataSecureErase": "Disabled",
"SaveUserDefaults": "No",
"SecureBoot": "Disabled",
"SecureBootStatus": "Disabled",
"SerialConsoleBaudRate": "115200",
"SerialConsoleEmulation": "Vt100Plus",
"SerialConsolePort": "Auto",
"ServerAssetTag": "",
"ServerName": "",
"ServerOtherInfo": "",
"ServerPrimaryOs": "",
"ServiceEmail": "",
"ServiceName": "",
"ServiceOtherInfo": "",
"ServicePhone": "",
"Slot1StorageBoot": "AllTargets",
"Slot2StorageBoot": "AllTargets",
"Slot3StorageBoot": "AllTargets",
"Slot4StorageBoot": "AllTargets",
"Slot5StorageBoot": "AllTargets",
"Slot6StorageBoot": "AllTargets",
"Sriov": "Enabled",
"TcmOperation": "Disable",
"TcmVisibility": "Visible",
"ThermalConfig": "OptimalCooling",
"ThermalShutdown": "Enabled",
"TimeZone": "UtcM7",
"Tpm2Operation": "NoAction",
"Tpm2Ppi": "Disabled",
"Tpm2Visibility": "Visible",
"TpmBinding": "Disabled",
"TpmOperation": "Disable",
"TpmState": "NotPresent",
"TpmType": "NoTpm",
"TpmUefiOpromMeasuring": "Enabled",
"TpmVisibility": "Visible",
"UefiOptimizedBoot": "Enabled",
"UefiPxeBoot": "Auto",
"UefiShellBootOrder": "Disabled",
"UefiShellStartup": "Disabled",
"UefiShellStartupLocation": "Auto",
"UefiShellStartupUrl": "",
"UrlBootFile": "",
"Usb3Mode": "Auto",
"UsbBoot": "Enabled",
"UsbControl": "UsbEnabled",
"UtilityLang": "English",
"VideoOptions": "BothVideoEnabled",
"VirtualInstallDisk": "Disabled",
"VirtualSerialPort": "Com2Irq3",
"VlanControl": "Disabled",
"VlanId": 0,
"VlanPriority": 0,
"WakeOnLan": "Enabled"
}
}
],
"Capabilities":
{
"BaseConfig": true,
"BaseConfigs": false
},
"Modified": "2015-03-26T00:05:15+00:00",
"Name": "BIOS Default Settings",
"Type": "HpBaseConfigs.0.10.0",
"links":
{
"self":
{
"href": "/rest/v1/systems/1/bios/BaseConfigs"
}
}
}
"""

View File

@@ -184,9 +184,19 @@ class IloRisTestCase(testtools.TestCase):
result = self.client.get_current_boot_mode()
self.assertEqual(result, 'LEGACY')
@mock.patch.object(ris.RISOperations, '_get_bios_settings_resource')
@mock.patch.object(ris.RISOperations, '_check_bios_resource')
def test_get_pending_boot_mode(self, check_mock, bios_mock):
check_mock.return_value = ('fake', 'fake',
json.loads(ris_outputs.GET_BIOS_SETTINGS))
bios_mock.return_value = ('fake', 'fake',
json.loads(ris_outputs.GET_BIOS_SETTINGS))
result = self.client.get_pending_boot_mode()
self.assertEqual(result, 'UEFI')
@mock.patch.object(ris.RISOperations, '_change_bios_setting')
def test_set_pending_boot_mode_bios(self, change_mock):
self.client.set_pending_boot_mode('bios')
def test_set_pending_boot_mode_legacy(self, change_mock):
self.client.set_pending_boot_mode('legacy')
change_mock.assert_called_once_with({'BootMode': 'LegacyBios'})
@mock.patch.object(ris.RISOperations, '_change_bios_setting')
@@ -239,8 +249,37 @@ class IloRisTestCase(testtools.TestCase):
self.client.reset_ilo_credential,
'fake-password')
def test_reset_bios_to_default(self):
pass
@mock.patch.object(ris.RISOperations, '_validate_if_patch_supported')
@mock.patch.object(ris.RISOperations, '_rest_patch')
@mock.patch.object(ris.RISOperations, '_get_bios_hash_password')
@mock.patch.object(ris.RISOperations, '_rest_get')
@mock.patch.object(ris.RISOperations, '_operation_allowed')
@mock.patch.object(ris.RISOperations, '_get_bios_settings_resource')
@mock.patch.object(ris.RISOperations, '_check_bios_resource')
def test_reset_bios_to_default(self, check_mock, bios_mock, op_mock,
get_mock, passwd_mock, patch_mock,
validate_mock):
settings_uri = '/rest/v1/systems/1/bios/Settings'
settings = json.loads(ris_outputs.GET_BIOS_SETTINGS)
base_config = json.loads(ris_outputs.GET_BASE_CONFIG)
default_config = base_config['BaseConfigs'][0]['default']
check_mock.return_value = (ris_outputs.GET_HEADERS, 'fake',
json.loads(ris_outputs.GET_BIOS_SETTINGS))
op_mock.return_value = False
passwd_mock.return_value = {}
get_mock.return_value = (200, 'fake', base_config)
bios_mock.return_value = (ris_outputs.GET_HEADERS,
settings_uri, {})
patch_mock.return_value = (200, 'fake', 'fake')
self.client.reset_bios_to_default()
check_mock.assert_called_once_with()
bios_mock.assert_called_once_with(settings)
op_mock.assert_called_once_with(ris_outputs.GET_HEADERS, 'PATCH')
get_mock.assert_called_once_with('/rest/v1/systems/1/bios/BaseConfigs')
passwd_mock.assert_called_once_with(None)
patch_mock.assert_called_once_with(settings_uri, {}, default_config)
validate_mock.assert_called_once_with(ris_outputs.GET_HEADERS,
settings_uri)
class TestRISOperationsPrivateMethods(testtools.TestCase):
@@ -443,16 +482,37 @@ class TestRISOperationsPrivateMethods(testtools.TestCase):
settings = json.loads(ris_outputs.GET_BIOS_SETTINGS)
check_bios_mock.return_value = (ris_outputs.GET_HEADERS,
bios_uri, settings)
patch_mock.return_value = (200, ris_outputs.REST_POST_RESPONSE,
patch_mock.return_value = (200, ris_outputs.GET_HEADERS,
ris_outputs.REST_POST_RESPONSE)
self.client._change_bios_setting(properties)
check_bios_mock.assert_called_once_with(properties.keys())
patch_mock.assert_called_once_with(bios_uri, {}, properties)
@mock.patch.object(ris.RISOperations, '_validate_if_patch_supported')
@mock.patch.object(ris.RISOperations, '_operation_allowed')
@mock.patch.object(ris.RISOperations, '_get_bios_settings_resource')
@mock.patch.object(ris.RISOperations, '_rest_patch')
@mock.patch.object(ris.RISOperations, '_check_bios_resource')
def test___change_bios_setting_fail(self, check_bios_mock, patch_mock):
pass
def test___change_bios_setting_fail(self, check_bios_mock, patch_mock,
settings_mock, op_mock,
validate_mock):
bios_uri = '/rest/v1/systems/1/bios/Settings'
properties = {'fake-property': 'fake-value'}
settings = json.loads(ris_outputs.GET_BIOS_SETTINGS)
op_mock.return_value = False
settings_mock.return_value = (ris_outputs.GET_HEADERS,
bios_uri, settings)
check_bios_mock.return_value = (ris_outputs.GET_HEADERS,
bios_uri, settings)
patch_mock.return_value = (301, ris_outputs.GET_HEADERS,
ris_outputs.REST_POST_RESPONSE)
self.assertRaises(exception.IloError,
self.client._change_bios_setting,
properties)
check_bios_mock.assert_called_once_with(properties.keys())
op_mock.assert_called_once_with(ris_outputs.GET_HEADERS, 'PATCH')
settings_mock.assert_called_once_with(settings)
patch_mock.assert_called_once_with(bios_uri, {}, properties)
@mock.patch.object(ris.RISOperations, '_change_bios_setting')
@mock.patch.object(ris.RISOperations, '_get_bios_setting')
@@ -502,5 +562,36 @@ class TestRISOperationsPrivateMethods(testtools.TestCase):
patch_mock.assert_called_once_with(secure_boot_uri, None,
{'fake-property': 'fake-value'})
def test__get_bios_setting(self):
pass
@mock.patch.object(ris.RISOperations, '_check_bios_resource')
def test__get_bios_setting(self, bios_mock):
bios_mock.return_value = ('fake', 'fake',
json.loads(ris_outputs.GET_BIOS_SETTINGS))
result = self.client._get_bios_setting('BootMode')
bios_mock.assert_called_once_with(['BootMode'])
self.assertEqual(result, 'Uefi')
@mock.patch.object(ris.RISOperations, '_rest_get')
def test__get_bios_settings_resource(self, get_mock):
settings = json.loads(ris_outputs.GET_BIOS_SETTINGS)
get_mock.return_value = (200, ris_outputs.GET_HEADERS,
settings)
self.client._get_bios_settings_resource(settings)
get_mock.assert_called_once_with('/rest/v1/systems/1/bios/Settings')
@mock.patch.object(ris.RISOperations, '_rest_get')
def test__get_bios_settings_resource_key_error(self, get_mock):
settings = json.loads(ris_outputs.GET_BASE_CONFIG)
self.assertRaises(exception.IloError,
self.client._get_bios_settings_resource,
settings)
@mock.patch.object(ris.RISOperations, '_rest_get')
def test__get_bios_settings_resource_fail(self, get_mock):
settings = json.loads(ris_outputs.GET_BIOS_SETTINGS)
settings_uri = '/rest/v1/systems/1/bios/Settings'
get_mock.return_value = (301, ris_outputs.GET_HEADERS,
settings)
self.assertRaises(exception.IloError,
self.client._get_bios_settings_resource,
settings)
get_mock.assert_called_once_with(settings_uri)