# # 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 re import lxml.etree import mock import requests_mock import dracclient.client from dracclient import constants from dracclient import exceptions from dracclient.resources import bios import dracclient.resources.job from dracclient.resources import lifecycle_controller from dracclient.resources import uris from dracclient.tests import base from dracclient.tests import utils as test_utils from dracclient import utils @requests_mock.Mocker() @mock.patch.object(dracclient.client.WSManClient, 'wait_until_idrac_is_ready', spec_set=True, autospec=True) class ClientPowerManagementTestCase(base.BaseTest): def setUp(self): super(ClientPowerManagementTestCase, self).setUp() self.drac_client = dracclient.client.DRACClient( **test_utils.FAKE_ENDPOINT) def test_get_power_state(self, mock_requests, mock_wait_until_idrac_is_ready): mock_requests.post( 'https://1.2.3.4:443/wsman', text=test_utils.BIOSEnumerations[uris.DCIM_ComputerSystem]['ok']) self.assertEqual('POWER_ON', self.drac_client.get_power_state()) def test_set_power_state(self, mock_requests, mock_wait_until_idrac_is_ready): mock_requests.post( 'https://1.2.3.4:443/wsman', text=test_utils.BIOSInvocations[ uris.DCIM_ComputerSystem]['RequestStateChange']['ok']) self.assertIsNone(self.drac_client.set_power_state('POWER_ON')) def test_set_power_state_fail(self, mock_requests, mock_wait_until_idrac_is_ready): mock_requests.post( 'https://1.2.3.4:443/wsman', text=test_utils.BIOSInvocations[ uris.DCIM_ComputerSystem]['RequestStateChange']['error']) self.assertRaises(exceptions.DRACOperationFailed, self.drac_client.set_power_state, 'POWER_ON') def test_set_power_state_invalid_target_state( self, mock_requests, mock_wait_until_idrac_is_ready): self.assertRaises(exceptions.InvalidParameterValue, self.drac_client.set_power_state, 'foo') @requests_mock.Mocker() @mock.patch.object(dracclient.client.WSManClient, 'wait_until_idrac_is_ready', spec_set=True, autospec=True) class ClientBootManagementTestCase(base.BaseTest): def setUp(self): super(ClientBootManagementTestCase, self).setUp() self.drac_client = dracclient.client.DRACClient( **test_utils.FAKE_ENDPOINT) def test_list_boot_modes(self, mock_requests, mock_wait_until_idrac_is_ready): expected_boot_mode = bios.BootMode(id='IPL', name='BootSeq', is_current=True, is_next=True) mock_requests.post( 'https://1.2.3.4:443/wsman', text=test_utils.BIOSEnumerations[ uris.DCIM_BootConfigSetting]['ok']) boot_modes = self.drac_client.list_boot_modes() self.assertEqual(5, len(boot_modes)) self.assertIn(expected_boot_mode, boot_modes) def test_list_boot_devices(self, mock_requests, mock_wait_until_idrac_is_ready): expected_boot_device = bios.BootDevice( id=('IPL:BIOS.Setup.1-1#BootSeq#NIC.Embedded.1-1-1#' 'fbeeb18f19fd4e768c941e66af4fc424'), boot_mode='IPL', pending_assigned_sequence=0, current_assigned_sequence=0, bios_boot_string=('Embedded NIC 1 Port 1 Partition 1: ' 'BRCM MBA Slot 0200 v16.4.3 BootSeq')) mock_requests.post( 'https://1.2.3.4:443/wsman', text=test_utils.BIOSEnumerations[ uris.DCIM_BootSourceSetting]['ok']) boot_devices = self.drac_client.list_boot_devices() self.assertEqual(3, len(boot_devices)) self.assertIn('IPL', boot_devices) self.assertIn('BCV', boot_devices) self.assertIn('UEFI', boot_devices) self.assertEqual(3, len(boot_devices['IPL'])) self.assertIn(expected_boot_device, boot_devices['IPL']) self.assertEqual( 0, boot_devices['IPL'][0].pending_assigned_sequence) self.assertEqual( 1, boot_devices['IPL'][1].pending_assigned_sequence) self.assertEqual( 2, boot_devices['IPL'][2].pending_assigned_sequence) @mock.patch.object(lifecycle_controller.LifecycleControllerManagement, 'get_version', spec_set=True, autospec=True) def test_list_boot_devices_11g(self, mock_requests, mock_get_lifecycle_controller_version, mock_wait_until_idrac_is_ready): expected_boot_device = bios.BootDevice( id=('IPL:NIC.Embedded.1-1:082927b7c62a9f52ef0d65a33416d76c'), boot_mode='IPL', pending_assigned_sequence=0, current_assigned_sequence=0, bios_boot_string=('Embedded NIC 1: ' 'BRCM MBA Slot 0200 v7.2.3 BootSeq')) mock_requests.post( 'https://1.2.3.4:443/wsman', text=test_utils.BIOSEnumerations[ uris.DCIM_BootSourceSetting]['ok-11g']) mock_get_lifecycle_controller_version.return_value = (1, 0, 0) boot_devices = self.drac_client.list_boot_devices() self.assertEqual(3, len(boot_devices)) self.assertIn('IPL', boot_devices) self.assertIn('BCV', boot_devices) self.assertIn('UEFI', boot_devices) self.assertEqual(3, len(boot_devices['IPL'])) self.assertIn(expected_boot_device, boot_devices['IPL']) self.assertEqual( 0, boot_devices['IPL'][0].pending_assigned_sequence) self.assertEqual( 1, boot_devices['IPL'][1].pending_assigned_sequence) self.assertEqual( 2, boot_devices['IPL'][2].pending_assigned_sequence) def test_change_boot_device_order(self, mock_requests, mock_wait_until_idrac_is_ready): mock_requests.post( 'https://1.2.3.4:443/wsman', text=test_utils.BIOSInvocations[ uris.DCIM_BootConfigSetting][ 'ChangeBootOrderByInstanceID']['ok']) self.assertIsNone( self.drac_client.change_boot_device_order('IPL', 'foo')) @mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True, autospec=True) def test_change_boot_device_order_list(self, mock_requests, mock_invoke, mock_wait_until_idrac_is_ready): expected_selectors = {'InstanceID': 'IPL'} expected_properties = {'source': ['foo', 'bar', 'baz']} mock_invoke.return_value = lxml.etree.fromstring( test_utils.BIOSInvocations[uris.DCIM_BootConfigSetting][ 'ChangeBootOrderByInstanceID']['ok']) self.drac_client.change_boot_device_order('IPL', ['foo', 'bar', 'baz']) mock_invoke.assert_called_once_with( mock.ANY, uris.DCIM_BootConfigSetting, 'ChangeBootOrderByInstanceID', expected_selectors, expected_properties, expected_return_value=utils.RET_SUCCESS) def test_change_boot_device_order_error(self, mock_requests, mock_wait_until_idrac_is_ready): mock_requests.post( 'https://1.2.3.4:443/wsman', text=test_utils.BIOSInvocations[ uris.DCIM_BootConfigSetting][ 'ChangeBootOrderByInstanceID']['error']) self.assertRaises( exceptions.DRACOperationFailed, self.drac_client.change_boot_device_order, 'IPL', 'foo') @requests_mock.Mocker() @mock.patch.object(dracclient.client.WSManClient, 'wait_until_idrac_is_ready', spec_set=True, autospec=True) class ClientBIOSConfigurationTestCase(base.BaseTest): def setUp(self): super(ClientBIOSConfigurationTestCase, self).setUp() self.drac_client = dracclient.client.DRACClient( **test_utils.FAKE_ENDPOINT) def test_list_bios_settings_by_instance_id(self, mock_requests, mock_wait_until_idrac_is_ready): expected_enum_attr = bios.BIOSEnumerableAttribute( name='MemTest', instance_id='BIOS.Setup.1-1:MemTest', read_only=False, current_value='Disabled', pending_value=None, possible_values=['Enabled', 'Disabled']) expected_string_attr = bios.BIOSStringAttribute( name='SystemModelName', instance_id='BIOS.Setup.1-1:SystemModelName', read_only=True, current_value='PowerEdge R320', pending_value=None, min_length=0, max_length=32, pcre_regex=None) expected_integer_attr = bios.BIOSIntegerAttribute( name='Proc1NumCores', instance_id='BIOS.Setup.1-1:Proc1NumCores', read_only=True, current_value=8, pending_value=None, lower_bound=0, upper_bound=65535) mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}]) bios_settings = self.drac_client.list_bios_settings(by_name=False) self.assertEqual(103, len(bios_settings)) # enumerable attribute self.assertIn('BIOS.Setup.1-1:MemTest', bios_settings) self.assertEqual(expected_enum_attr, bios_settings[ 'BIOS.Setup.1-1:MemTest']) # string attribute self.assertIn('BIOS.Setup.1-1:SystemModelName', bios_settings) self.assertEqual(expected_string_attr, bios_settings['BIOS.Setup.1-1:SystemModelName']) # integer attribute self.assertIn('BIOS.Setup.1-1:Proc1NumCores', bios_settings) self.assertEqual(expected_integer_attr, bios_settings[ 'BIOS.Setup.1-1:Proc1NumCores']) def test_list_bios_settings_by_name(self, mock_requests, mock_wait_until_idrac_is_ready): expected_enum_attr = bios.BIOSEnumerableAttribute( name='MemTest', instance_id='BIOS.Setup.1-1:MemTest', read_only=False, current_value='Disabled', pending_value=None, possible_values=['Enabled', 'Disabled']) expected_string_attr = bios.BIOSStringAttribute( name='SystemModelName', instance_id='BIOS.Setup.1-1:SystemModelName', read_only=True, current_value='PowerEdge R320', pending_value=None, min_length=0, max_length=32, pcre_regex=None) expected_integer_attr = bios.BIOSIntegerAttribute( name='Proc1NumCores', instance_id='BIOS.Setup.1-1:Proc1NumCores', read_only=True, current_value=8, pending_value=None, lower_bound=0, upper_bound=65535) mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}]) bios_settings = self.drac_client.list_bios_settings(by_name=True) self.assertEqual(103, len(bios_settings)) # enumerable attribute self.assertIn('MemTest', bios_settings) self.assertEqual(expected_enum_attr, bios_settings['MemTest']) # string attribute self.assertIn('SystemModelName', bios_settings) self.assertEqual(expected_string_attr, bios_settings['SystemModelName']) # integer attribute self.assertIn('Proc1NumCores', bios_settings) self.assertEqual(expected_integer_attr, bios_settings['Proc1NumCores']) def test_list_bios_settings_by_name_with_colliding_attrs( self, mock_requests, mock_wait_until_idrac_is_ready): mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['colliding']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}]) self.assertRaises(exceptions.DRACOperationFailed, self.drac_client.list_bios_settings, by_name=True) @mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True, autospec=True) def test_set_bios_settings(self, mock_requests, mock_invoke, mock_wait_until_idrac_is_ready): expected_selectors = {'CreationClassName': 'DCIM_BIOSService', 'SystemName': 'DCIM:ComputerSystem', 'Name': 'DCIM:BIOSService', 'SystemCreationClassName': 'DCIM_ComputerSystem'} expected_properties = {'Target': 'BIOS.Setup.1-1', 'AttributeName': ['ProcVirtualization'], 'AttributeValue': ['Disabled']} mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}]) mock_invoke.return_value = lxml.etree.fromstring( test_utils.BIOSInvocations[uris.DCIM_BIOSService][ 'SetAttributes']['ok']) result = self.drac_client.set_bios_settings( {'ProcVirtualization': 'Disabled'}) self.assertEqual({'is_commit_required': True, 'is_reboot_required': constants.RebootRequired.true}, result) mock_invoke.assert_called_once_with( mock.ANY, uris.DCIM_BIOSService, 'SetAttributes', expected_selectors, expected_properties) def test_set_bios_settings_error(self, mock_requests, mock_wait_until_idrac_is_ready): mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}, {'text': test_utils.BIOSInvocations[ uris.DCIM_BIOSService]['SetAttributes']['error']}]) self.assertRaises(exceptions.DRACOperationFailed, self.drac_client.set_bios_settings, {'ProcVirtualization': 'Disabled'}) def test_set_bios_settings_with_unknown_attr( self, mock_requests, mock_wait_until_idrac_is_ready): mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}]) self.assertRaises(exceptions.InvalidParameterValue, self.drac_client.set_bios_settings, {'foo': 'bar'}) def test_set_bios_settings_with_unchanged_attr( self, mock_requests, mock_wait_until_idrac_is_ready): mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}]) result = self.drac_client.set_bios_settings( {'ProcVirtualization': 'Enabled'}) self.assertEqual({'is_commit_required': False, 'is_reboot_required': constants.RebootRequired.false}, result) def test_set_bios_settings_with_readonly_attr( self, mock_requests, mock_wait_until_idrac_is_ready): expected_message = ("Cannot set read-only BIOS attributes: " "['Proc1NumCores'].") mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}]) self.assertRaisesRegexp( exceptions.DRACOperationFailed, re.escape(expected_message), self.drac_client.set_bios_settings, {'Proc1NumCores': 42}) def test_set_bios_settings_with_incorrect_enum_value( self, mock_requests, mock_wait_until_idrac_is_ready): expected_message = ("Attribute 'MemTest' cannot be set to value " "'foo'. It must be in ['Enabled', 'Disabled'].") mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}]) self.assertRaisesRegexp( exceptions.DRACOperationFailed, re.escape(expected_message), self.drac_client.set_bios_settings, {'MemTest': 'foo'}) def test_set_bios_settings_with_incorrect_regexp( self, mock_requests, mock_wait_until_idrac_is_ready): expected_message = ("Attribute 'SystemModelName' cannot be set to " "value 'bar.' It must match regex 'foo'.") mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['regexp']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['ok']}]) self.assertRaisesRegexp( exceptions.DRACOperationFailed, re.escape(expected_message), self.drac_client.set_bios_settings, {'SystemModelName': 'bar'}) def test_set_bios_settings_with_out_of_bounds_value( self, mock_requests, mock_wait_until_idrac_is_ready): expected_message = ('Attribute Proc1NumCores cannot be set to value ' '-42. It must be between 0 and 65535.') mock_requests.post('https://1.2.3.4:443/wsman', [ {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSEnumeration]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSString]['ok']}, {'text': test_utils.BIOSEnumerations[ uris.DCIM_BIOSInteger]['mutable']}]) self.assertRaisesRegexp( exceptions.DRACOperationFailed, re.escape(expected_message), self.drac_client.set_bios_settings, {'Proc1NumCores': -42}) class ClientBIOSChangesTestCase(base.BaseTest): def setUp(self): super(ClientBIOSChangesTestCase, self).setUp() self.drac_client = dracclient.client.DRACClient( **test_utils.FAKE_ENDPOINT) @mock.patch.object(dracclient.resources.job.JobManagement, 'create_config_job', spec_set=True, autospec=True) def test_commit_pending_bios_changes(self, mock_create_config_job): self.drac_client.commit_pending_bios_changes() mock_create_config_job.assert_called_once_with( mock.ANY, resource_uri=uris.DCIM_BIOSService, cim_creation_class_name='DCIM_BIOSService', cim_name='DCIM:BIOSService', target='BIOS.Setup.1-1', reboot=False, start_time='TIME_NOW') @mock.patch.object(dracclient.resources.job.JobManagement, 'create_config_job', spec_set=True, autospec=True) def test_commit_pending_bios_changes_with_reboot(self, mock_create_config_job): self.drac_client.commit_pending_bios_changes(reboot=True) mock_create_config_job.assert_called_once_with( mock.ANY, resource_uri=uris.DCIM_BIOSService, cim_creation_class_name='DCIM_BIOSService', cim_name='DCIM:BIOSService', target='BIOS.Setup.1-1', reboot=True, start_time='TIME_NOW') @mock.patch.object(dracclient.resources.job.JobManagement, 'create_config_job', spec_set=True, autospec=True) def test_commit_pending_bios_changes_with_time( self, mock_create_config_job): timestamp = '20140924140201' self.drac_client.commit_pending_bios_changes( start_time=timestamp) mock_create_config_job.assert_called_once_with( mock.ANY, resource_uri=uris.DCIM_BIOSService, cim_creation_class_name='DCIM_BIOSService', cim_name='DCIM:BIOSService', target='BIOS.Setup.1-1', reboot=False, start_time=timestamp) @mock.patch.object(dracclient.resources.job.JobManagement, 'create_config_job', spec_set=True, autospec=True) def test_commit_pending_bios_changes_with_reboot_and_time( self, mock_create_config_job): timestamp = '20140924140201' self.drac_client.commit_pending_bios_changes( reboot=True, start_time=timestamp) mock_create_config_job.assert_called_once_with( mock.ANY, resource_uri=uris.DCIM_BIOSService, cim_creation_class_name='DCIM_BIOSService', cim_name='DCIM:BIOSService', target='BIOS.Setup.1-1', reboot=True, start_time=timestamp) @mock.patch.object(dracclient.resources.job.JobManagement, 'delete_pending_config', spec_set=True, autospec=True) def test_abandon_pending_bios_changes(self, mock_delete_pending_config): self.drac_client.abandon_pending_bios_changes() mock_delete_pending_config.assert_called_once_with( mock.ANY, resource_uri=uris.DCIM_BIOSService, cim_creation_class_name='DCIM_BIOSService', cim_name='DCIM:BIOSService', target='BIOS.Setup.1-1')