Add ability to schedule jobs

Adds an optional start time to allow configuration changes
to be scheduled for a future time.

Co-Authored-By: Christopher Dearborn <christopher.dearborn@dell.com>
Co-Authored-By: Richard G. Pioso <richard.pioso@dell.com>
Change-Id: Ia1f02fd2f8a25efa8bb924bd9d50394cbf5d2034
This commit is contained in:
Mark Beierl 2018-06-25 16:39:14 -04:00
parent a300f85654
commit dcf4e2d280
7 changed files with 447 additions and 32 deletions

View File

@ -244,11 +244,17 @@ class DRACClient(object):
def commit_pending_idrac_changes( def commit_pending_idrac_changes(
self, self,
idrac_fqdd=IDRAC_FQDD, idrac_fqdd=IDRAC_FQDD,
reboot=False): reboot=False,
"""Creates a config job for applying all pending changes to an iDRAC start_time='TIME_NOW'):
"""Create a config job for applying all pending iDRAC changes.
:param idrac_fqdd: the FQDD of the iDRAC. :param idrac_fqdd: the FQDD of the iDRAC.
:param reboot: indication of whether to also create a reboot job :param reboot: indication of whether to also create a reboot job
:param start_time: start time for job execution in format
yyyymmddhhmmss, the string 'TIME_NOW' which
means execute immediately or None which means
the job will not execute until
schedule_job_execution is called
:returns: id of the created configuration job :returns: id of the created configuration job
:raises: WSManRequestFailure on request failures :raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response :raises: WSManInvalidResponse when receiving invalid response
@ -261,7 +267,8 @@ class DRACClient(object):
cim_creation_class_name='DCIM_iDRACCardService', cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService', cim_name='DCIM:iDRACCardService',
target=idrac_fqdd, target=idrac_fqdd,
reboot=reboot) reboot=reboot,
start_time=start_time)
def abandon_pending_idrac_changes(self, idrac_fqdd=IDRAC_FQDD): def abandon_pending_idrac_changes(self, idrac_fqdd=IDRAC_FQDD):
"""Abandon all pending changes to an iDRAC """Abandon all pending changes to an iDRAC
@ -332,12 +339,16 @@ class DRACClient(object):
""" """
return self._job_mgmt.get_job(job_id) return self._job_mgmt.get_job(job_id)
def create_config_job(self, resource_uri, cim_creation_class_name, def create_config_job(self,
cim_name, target, resource_uri,
cim_creation_class_name,
cim_name,
target,
cim_system_creation_class_name='DCIM_ComputerSystem', cim_system_creation_class_name='DCIM_ComputerSystem',
cim_system_name='DCIM:ComputerSystem', cim_system_name='DCIM:ComputerSystem',
reboot=False): reboot=False,
"""Creates a config job start_time='TIME_NOW'):
"""Creates a configuration job.
In CIM (Common Information Model), weak association is used to name an In CIM (Common Information Model), weak association is used to name an
instance of one class in the context of an instance of another class. instance of one class in the context of an instance of another class.
@ -353,18 +364,62 @@ class DRACClient(object):
:param cim_system_creation_class_name: creation class name of the :param cim_system_creation_class_name: creation class name of the
scoping system scoping system
:param cim_system_name: name of the scoping system :param cim_system_name: name of the scoping system
:param reboot: indicates whether a RebootJob should also be :param reboot: indicates whether or not a RebootJob should also be
created or not created
:param start_time: start time for job execution in format
yyyymmddhhmmss, the string 'TIME_NOW' which
means execute immediately or None which means
the job will not execute until
schedule_job_execution is called
:returns: id of the created job :returns: id of the created job
:raises: WSManRequestFailure on request failures :raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response :raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the DRAC :raises: DRACOperationFailed on error reported back by the iDRAC
interface interface
:raises: DRACUnexpectedReturnValue on return value mismatch :raises: DRACUnexpectedReturnValue on return value mismatch
""" """
return self._job_mgmt.create_config_job( return self._job_mgmt.create_config_job(
resource_uri, cim_creation_class_name, cim_name, target, resource_uri=resource_uri,
cim_system_creation_class_name, cim_system_name, reboot) cim_creation_class_name=cim_creation_class_name,
cim_name=cim_name,
target=target,
cim_system_creation_class_name=cim_system_creation_class_name,
cim_system_name=cim_system_name,
reboot=reboot,
start_time=start_time)
def create_reboot_job(self,
reboot_type='graceful_reboot_with_forced_shutdown'):
"""Creates a reboot job.
:param reboot_type: type of reboot
:returns id of the created job
:raises: InvalidParameterValue on invalid reboot type
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the iDRAC
interface
:raises: DRACUnexpectedReturnValue on return value mismatch
"""
return self._job_mgmt.create_reboot_job(reboot_type)
def schedule_job_execution(self, job_ids, start_time='TIME_NOW'):
"""Schedules jobs for execution in a specified order.
:param job_ids: list of job identifiers
:param start_time: start time for job execution in format
yyyymmddhhmmss or the string 'TIME_NOW' which
means execute immediately. None is not a
valid option for this request.
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the iDRAC
interface, including start_time being in the past or
badly formatted start_time
:raises: DRACUnexpectedReturnValue on return value mismatch
"""
return self._job_mgmt.schedule_job_execution(job_ids, start_time)
def delete_pending_config( def delete_pending_config(
self, resource_uri, cim_creation_class_name, cim_name, target, self, resource_uri, cim_creation_class_name, cim_name, target,
@ -398,23 +453,34 @@ class DRACClient(object):
resource_uri, cim_creation_class_name, cim_name, target, resource_uri, cim_creation_class_name, cim_name, target,
cim_system_creation_class_name, cim_system_name) cim_system_creation_class_name, cim_system_name)
def commit_pending_bios_changes(self, reboot=False): def commit_pending_bios_changes(
self,
reboot=False,
start_time='TIME_NOW'):
"""Applies all pending changes on the BIOS by creating a config job """Applies all pending changes on the BIOS by creating a config job
:param reboot: indicates whether a RebootJob should also be :param reboot: indicates whether a RebootJob should also be
created or not created or not
:param start_time: start time for job execution in format
yyyymmddhhmmss, the string 'TIME_NOW' which
means execute immediately or None which means
the job will not execute until
schedule_job_execution is called
:returns: id of the created job :returns: id of the created job
:raises: WSManRequestFailure on request failures :raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response :raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the DRAC :raises: DRACOperationFailed on error reported back by the DRAC
interface interface, including start_time being in the past or
badly formatted start_time
:raises: DRACUnexpectedReturnValue on return value mismatch :raises: DRACUnexpectedReturnValue on return value mismatch
""" """
return self._job_mgmt.create_config_job( return self._job_mgmt.create_config_job(
resource_uri=uris.DCIM_BIOSService, resource_uri=uris.DCIM_BIOSService,
cim_creation_class_name='DCIM_BIOSService', cim_creation_class_name='DCIM_BIOSService',
cim_name='DCIM:BIOSService', target=self.BIOS_DEVICE_FQDD, cim_name='DCIM:BIOSService',
reboot=reboot) target=self.BIOS_DEVICE_FQDD,
reboot=reboot,
start_time=start_time)
def abandon_pending_bios_changes(self): def abandon_pending_bios_changes(self):
"""Deletes all pending changes on the BIOS """Deletes all pending changes on the BIOS
@ -569,7 +635,8 @@ class DRACClient(object):
""" """
return self._raid_mgmt.delete_virtual_disk(virtual_disk) return self._raid_mgmt.delete_virtual_disk(virtual_disk)
def commit_pending_raid_changes(self, raid_controller, reboot=False): def commit_pending_raid_changes(self, raid_controller, reboot=False,
start_time='TIME_NOW'):
"""Applies all pending changes on a RAID controller """Applies all pending changes on a RAID controller
...by creating a config job. ...by creating a config job.
@ -577,6 +644,11 @@ class DRACClient(object):
:param raid_controller: id of the RAID controller :param raid_controller: id of the RAID controller
:param reboot: indicates whether a RebootJob should also be :param reboot: indicates whether a RebootJob should also be
created or not created or not
:param start_time: start time for job execution in format
yyyymmddhhmmss, the string 'TIME_NOW' which
means execute immediately or None which means
the job will not execute until
schedule_job_execution is called
:returns: id of the created job :returns: id of the created job
:raises: WSManRequestFailure on request failures :raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response :raises: WSManInvalidResponse when receiving invalid response
@ -587,7 +659,10 @@ class DRACClient(object):
return self._job_mgmt.create_config_job( return self._job_mgmt.create_config_job(
resource_uri=uris.DCIM_RAIDService, resource_uri=uris.DCIM_RAIDService,
cim_creation_class_name='DCIM_RAIDService', cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target=raid_controller, reboot=reboot) cim_name='DCIM:RAIDService',
target=raid_controller,
reboot=reboot,
start_time=start_time)
def abandon_pending_raid_changes(self, raid_controller): def abandon_pending_raid_changes(self, raid_controller):
"""Deletes all pending changes on a RAID controller """Deletes all pending changes on a RAID controller

View File

@ -14,6 +14,7 @@
import collections import collections
import logging import logging
import dracclient.exceptions as exceptions
from dracclient.resources import uris from dracclient.resources import uris
from dracclient import utils from dracclient import utils
from dracclient import wsman from dracclient import wsman
@ -25,6 +26,12 @@ JobTuple = collections.namedtuple(
['id', 'name', 'start_time', 'until_time', 'message', 'status', ['id', 'name', 'start_time', 'until_time', 'message', 'status',
'percent_complete']) 'percent_complete'])
REBOOT_TYPES = {
'power_cycle': '1',
'graceful_reboot_without_forced_shutdown': '2',
'graceful_reboot_with_forced_shutdown': '3',
}
class Job(JobTuple): class Job(JobTuple):
@ -108,7 +115,8 @@ class JobManagement(object):
cim_name, target, cim_name, target,
cim_system_creation_class_name='DCIM_ComputerSystem', cim_system_creation_class_name='DCIM_ComputerSystem',
cim_system_name='DCIM:ComputerSystem', cim_system_name='DCIM:ComputerSystem',
reboot=False): reboot=False,
start_time='TIME_NOW'):
"""Creates a config job """Creates a config job
In CIM (Common Information Model), weak association is used to name an In CIM (Common Information Model), weak association is used to name an
@ -127,6 +135,12 @@ class JobManagement(object):
:param cim_system_name: name of the scoping system :param cim_system_name: name of the scoping system
:param reboot: indicates whether a RebootJob should also be created or :param reboot: indicates whether a RebootJob should also be created or
not not
:param start_time: start time for job execution in format
yyyymmddhhmmss; the string 'TIME_NOW' means
immediately and None means the job is registered
but will not start execution until
schedule_job_execution is called with the returned
job id.
:returns: id of the created job :returns: id of the created job
:raises: WSManRequestFailure on request failures :raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response :raises: WSManInvalidResponse when receiving invalid response
@ -140,21 +154,98 @@ class JobManagement(object):
'CreationClassName': cim_creation_class_name, 'CreationClassName': cim_creation_class_name,
'Name': cim_name} 'Name': cim_name}
properties = {'Target': target, properties = {'Target': target}
'ScheduledStartTime': 'TIME_NOW'}
if reboot: if reboot:
properties['RebootJobType'] = '3' properties['RebootJobType'] = '3'
if start_time is not None:
properties['ScheduledStartTime'] = start_time
doc = self.client.invoke(resource_uri, 'CreateTargetedConfigJob', doc = self.client.invoke(resource_uri, 'CreateTargetedConfigJob',
selectors, properties, selectors, properties,
expected_return_value=utils.RET_CREATED) expected_return_value=utils.RET_CREATED)
query = ('.//{%(namespace)s}%(item)s[@%(attribute_name)s=' return self._get_job_id(doc)
'"%(attribute_value)s"]' %
{'namespace': wsman.NS_WSMAN, 'item': 'Selector', def create_reboot_job(self,
'attribute_name': 'Name', reboot_type='graceful_reboot_with_forced_shutdown'):
'attribute_value': 'InstanceID'}) """Creates a reboot job.
:param reboot_type: type of reboot
:returns id of the created job
:raises: InvalidParameterValue on invalid reboot type
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the iDRAC
interface
:raises: DRACUnexpectedReturnValue on return value mismatch
"""
try:
drac_reboot_type = REBOOT_TYPES[reboot_type]
except KeyError:
msg = ("'%(reboot_type)s' is not supported. "
"Supported reboot types: %(supported_reboot_types)r") % {
'reboot_type': reboot_type,
'supported_reboot_types': list(REBOOT_TYPES)}
raise exceptions.InvalidParameterValue(reason=msg)
selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
'SystemName': 'idrac',
'CreationClassName': 'DCIM_JobService',
'Name': 'JobService'}
properties = {'RebootJobType': drac_reboot_type}
doc = self.client.invoke(uris.DCIM_JobService,
'CreateRebootJob',
selectors,
properties,
expected_return_value=utils.RET_CREATED)
return self._get_job_id(doc)
def schedule_job_execution(self, job_ids, start_time='TIME_NOW'):
"""Schedules jobs for execution in a specified order.
:param job_ids: list of job identifiers
:param start_time: start time for job execution in format
yyyymmddhhmmss; the string 'TIME_NOW' means
immediately
:raises: WSManRequestFailure on request failures
:raises: WSManInvalidResponse when receiving invalid response
:raises: DRACOperationFailed on error reported back by the iDRAC
interface
:raises: DRACUnexpectedReturnValue on return value mismatch
"""
# If the list of job identifiers is empty, there is nothing to do.
if not job_ids:
return
selectors = {'SystemCreationClassName': 'DCIM_ComputerSystem',
'SystemName': 'idrac',
'CreationClassName': 'DCIM_JobService',
'Name': 'JobService'}
properties = {'JobArray': job_ids,
'StartTimeInterval': start_time}
self.client.invoke(uris.DCIM_JobService,
'SetupJobQueue',
selectors,
properties,
expected_return_value=utils.RET_SUCCESS)
def _get_job_id(self, doc):
query = (
'.//{%(namespace)s}%(item)s[@%(attribute_name)s='
'"%(attribute_value)s"]' % {
'namespace': wsman.NS_WSMAN,
'item': 'Selector',
'attribute_name': 'Name',
'attribute_value': 'InstanceID'})
job_id = doc.find(query).text job_id = doc.find(query).text
return job_id return job_id

View File

@ -55,6 +55,9 @@ DCIM_iDRACCardService = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
DCIM_iDRACCardString = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/' DCIM_iDRACCardString = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
'DCIM_iDRACCardString') 'DCIM_iDRACCardString')
DCIM_JobService = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
'DCIM_JobService')
DCIM_LCEnumeration = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/' DCIM_LCEnumeration = ('http://schemas.dell.com/wbem/wscim/1/cim-schema/2/'
'DCIM_LCEnumeration') 'DCIM_LCEnumeration')

View File

@ -484,7 +484,8 @@ class ClientBIOSChangesTestCase(base.BaseTest):
mock_create_config_job.assert_called_once_with( mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_BIOSService, mock.ANY, resource_uri=uris.DCIM_BIOSService,
cim_creation_class_name='DCIM_BIOSService', cim_creation_class_name='DCIM_BIOSService',
cim_name='DCIM:BIOSService', target='BIOS.Setup.1-1', reboot=False) cim_name='DCIM:BIOSService', target='BIOS.Setup.1-1',
reboot=False, start_time='TIME_NOW')
@mock.patch.object(dracclient.resources.job.JobManagement, @mock.patch.object(dracclient.resources.job.JobManagement,
'create_config_job', spec_set=True, autospec=True) 'create_config_job', spec_set=True, autospec=True)
@ -495,7 +496,38 @@ class ClientBIOSChangesTestCase(base.BaseTest):
mock_create_config_job.assert_called_once_with( mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_BIOSService, mock.ANY, resource_uri=uris.DCIM_BIOSService,
cim_creation_class_name='DCIM_BIOSService', cim_creation_class_name='DCIM_BIOSService',
cim_name='DCIM:BIOSService', target='BIOS.Setup.1-1', reboot=True) 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, @mock.patch.object(dracclient.resources.job.JobManagement,
'delete_pending_config', spec_set=True, autospec=True) 'delete_pending_config', spec_set=True, autospec=True)

View File

@ -283,7 +283,7 @@ class ClientiDRACCardChangesTestCase(base.BaseTest):
cim_creation_class_name='DCIM_iDRACCardService', cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService', cim_name='DCIM:iDRACCardService',
target=dracclient.client.DRACClient.IDRAC_FQDD, target=dracclient.client.DRACClient.IDRAC_FQDD,
reboot=False) reboot=False, start_time='TIME_NOW')
@mock.patch.object(job.JobManagement, 'create_config_job', spec_set=True, @mock.patch.object(job.JobManagement, 'create_config_job', spec_set=True,
autospec=True) autospec=True)
@ -299,7 +299,41 @@ class ClientiDRACCardChangesTestCase(base.BaseTest):
cim_creation_class_name='DCIM_iDRACCardService', cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService', cim_name='DCIM:iDRACCardService',
target=dracclient.client.DRACClient.IDRAC_FQDD, target=dracclient.client.DRACClient.IDRAC_FQDD,
reboot=True) reboot=True, start_time='TIME_NOW')
@mock.patch.object(job.JobManagement, 'create_config_job', spec_set=True,
autospec=True)
def test_commit_pending_idrac_changes_with_time(
self, mock_create_config_job):
timestamp = '20140924120101'
self.drac_client.commit_pending_idrac_changes(
start_time=timestamp)
mock_create_config_job.assert_called_once_with(
mock.ANY,
resource_uri=uris.DCIM_iDRACCardService,
cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService',
target=dracclient.client.DRACClient.IDRAC_FQDD,
reboot=False, start_time=timestamp)
@mock.patch.object(job.JobManagement, 'create_config_job', spec_set=True,
autospec=True)
def test_commit_pending_idrac_changes_with_reboot_and_time(
self, mock_create_config_job):
timestamp = '20140924120101'
self.drac_client.commit_pending_idrac_changes(
reboot=True,
start_time=timestamp)
mock_create_config_job.assert_called_once_with(
mock.ANY,
resource_uri=uris.DCIM_iDRACCardService,
cim_creation_class_name='DCIM_iDRACCardService',
cim_name='DCIM:iDRACCardService',
target=dracclient.client.DRACClient.IDRAC_FQDD,
reboot=True, start_time=timestamp)
@mock.patch.object(job.JobManagement, 'delete_pending_config', @mock.patch.object(job.JobManagement, 'delete_pending_config',
spec_set=True, autospec=True) spec_set=True, autospec=True)

View File

@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import datetime
import lxml.etree import lxml.etree
import mock import mock
import requests_mock import requests_mock
@ -127,6 +128,59 @@ class ClientJobManagementTestCase(base.BaseTest):
expected_return_value=utils.RET_CREATED) expected_return_value=utils.RET_CREATED)
self.assertEqual('JID_442507917525', job_id) self.assertEqual('JID_442507917525', job_id)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_create_config_job_with_start_time(self, mock_invoke):
cim_creation_class_name = 'DCIM_BIOSService'
cim_name = 'DCIM:BIOSService'
target = 'BIOS.Setup.1-1'
start_time = "20140924120105"
expected_selectors = {'CreationClassName': cim_creation_class_name,
'Name': cim_name,
'SystemCreationClassName': 'DCIM_ComputerSystem',
'SystemName': 'DCIM:ComputerSystem'}
expected_properties = {'Target': target,
'ScheduledStartTime': start_time}
mock_invoke.return_value = lxml.etree.fromstring(
test_utils.JobInvocations[uris.DCIM_BIOSService][
'CreateTargetedConfigJob']['ok'])
job_id = self.drac_client.create_config_job(
uris.DCIM_BIOSService, cim_creation_class_name, cim_name, target,
start_time=start_time)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_BIOSService, 'CreateTargetedConfigJob',
expected_selectors, expected_properties,
expected_return_value=utils.RET_CREATED)
self.assertEqual('JID_442507917525', job_id)
@mock.patch.object(dracclient.client.WSManClient, 'invoke',
spec_set=True, autospec=True)
def test_create_config_job_with_no_start_time(self, mock_invoke):
cim_creation_class_name = 'DCIM_BIOSService'
cim_name = 'DCIM:BIOSService'
target = 'BIOS.Setup.1-1'
start_time = None
expected_selectors = {'CreationClassName': cim_creation_class_name,
'Name': cim_name,
'SystemCreationClassName': 'DCIM_ComputerSystem',
'SystemName': 'DCIM:ComputerSystem'}
expected_properties = {'Target': target}
mock_invoke.return_value = lxml.etree.fromstring(
test_utils.JobInvocations[uris.DCIM_BIOSService][
'CreateTargetedConfigJob']['ok'])
job_id = self.drac_client.create_config_job(
uris.DCIM_BIOSService, cim_creation_class_name, cim_name, target,
start_time=start_time)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_BIOSService, 'CreateTargetedConfigJob',
expected_selectors, expected_properties,
expected_return_value=utils.RET_CREATED)
self.assertEqual('JID_442507917525', job_id)
@requests_mock.Mocker() @requests_mock.Mocker()
@mock.patch.object(dracclient.client.WSManClient, @mock.patch.object(dracclient.client.WSManClient,
'wait_until_idrac_is_ready', spec_set=True, 'wait_until_idrac_is_ready', spec_set=True,
@ -172,6 +226,27 @@ class ClientJobManagementTestCase(base.BaseTest):
expected_return_value=utils.RET_CREATED) expected_return_value=utils.RET_CREATED)
self.assertEqual('JID_442507917525', job_id) self.assertEqual('JID_442507917525', job_id)
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
autospec=True)
def test_create_reboot_job(self, mock_invoke):
expected_selectors = {
'SystemCreationClassName': 'DCIM_ComputerSystem',
'SystemName': 'idrac',
'CreationClassName': 'DCIM_JobService',
'Name': 'JobService'}
expected_properties = {'RebootJobType': '3'}
self.drac_client.create_reboot_job()
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_JobService, 'CreateRebootJob',
expected_selectors, expected_properties,
expected_return_value=utils.RET_CREATED)
def test_create_reboot_job_bad_type(self):
self.assertRaises(
exceptions.InvalidParameterValue,
self.drac_client.create_reboot_job, 'BAD REBOOT TYPE')
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True, @mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
autospec=True) autospec=True)
def test_delete_pending_config(self, mock_invoke): def test_delete_pending_config(self, mock_invoke):
@ -213,3 +288,75 @@ class ClientJobManagementTestCase(base.BaseTest):
exceptions.DRACOperationFailed, exceptions.DRACOperationFailed,
self.drac_client.delete_pending_config, uris.DCIM_BIOSService, self.drac_client.delete_pending_config, uris.DCIM_BIOSService,
cim_creation_class_name, cim_name, target) cim_creation_class_name, cim_name, target)
class ClientJobScheduleTestCase(base.BaseTest):
def setUp(self):
super(ClientJobScheduleTestCase, self).setUp()
self.drac_client = dracclient.client.DRACClient(
**test_utils.FAKE_ENDPOINT)
def _test_schedule_job_execution(self,
mock_invoke,
job_ids,
start_time,
expected_properties):
expected_selectors = {
'SystemCreationClassName': 'DCIM_ComputerSystem',
'SystemName': 'idrac',
'CreationClassName': 'DCIM_JobService',
'Name': 'JobService'}
if start_time is None:
self.drac_client.schedule_job_execution(job_ids)
else:
self.drac_client.schedule_job_execution(job_ids, start_time)
mock_invoke.assert_called_once_with(
mock.ANY, uris.DCIM_JobService, 'SetupJobQueue',
expected_selectors, expected_properties,
expected_return_value=utils.RET_SUCCESS)
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
autospec=True)
def test_schedule_job_execution_one_job(self, mock_invoke):
job_ids = ['JID_442507917525']
expected_properties = {'StartTimeInterval': 'TIME_NOW',
'JobArray': job_ids}
self._test_schedule_job_execution(mock_invoke, job_ids, None,
expected_properties)
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
autospec=True)
def test_schedule_job_execution_multi_job(self, mock_invoke):
job_ids = ['JID_442507917525', 'JID_442507917526']
expected_properties = {'StartTimeInterval': 'TIME_NOW',
'JobArray': job_ids}
self._test_schedule_job_execution(mock_invoke, job_ids, None,
expected_properties)
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
autospec=True)
def test_schedule_job_execution_one_job_with_time(self, mock_invoke):
job_ids = ['JID_442507917525']
timestamp = datetime.datetime.today().strftime('%Y%m%d%H%M%S')
expected_properties = {'StartTimeInterval': timestamp,
'JobArray': job_ids}
self._test_schedule_job_execution(mock_invoke, job_ids, timestamp,
expected_properties)
@mock.patch.object(dracclient.client.WSManClient, 'invoke', spec_set=True,
autospec=True)
def test_schedule_job_execution_multi_job_with_time(self, mock_invoke):
job_ids = ['JID_442507917525', 'JID_442507917526']
timestamp = datetime.datetime.today().strftime('%Y%m%d%H%M%S')
expected_properties = {'StartTimeInterval': timestamp,
'JobArray': job_ids}
self._test_schedule_job_execution(mock_invoke, job_ids, timestamp,
expected_properties)
@mock.patch.object(dracclient.client.WSManClient, 'invoke')
def test_schedule_job_execution_no_jobs(self, mock_invoke):
self.drac_client.schedule_job_execution(job_ids=[])
mock_invoke.assert_not_called()

View File

@ -507,7 +507,8 @@ class ClientRAIDManagementTestCase(base.BaseTest):
mock_create_config_job.assert_called_once_with( mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_RAIDService, mock.ANY, resource_uri=uris.DCIM_RAIDService,
cim_creation_class_name='DCIM_RAIDService', cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target='controller', reboot=False) cim_name='DCIM:RAIDService', target='controller', reboot=False,
start_time='TIME_NOW')
@mock.patch.object(dracclient.resources.job.JobManagement, @mock.patch.object(dracclient.resources.job.JobManagement,
'create_config_job', spec_set=True, autospec=True) 'create_config_job', spec_set=True, autospec=True)
@ -518,7 +519,39 @@ class ClientRAIDManagementTestCase(base.BaseTest):
mock_create_config_job.assert_called_once_with( mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_RAIDService, mock.ANY, resource_uri=uris.DCIM_RAIDService,
cim_creation_class_name='DCIM_RAIDService', cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target='controller', reboot=True) cim_name='DCIM:RAIDService', target='controller', 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_raid_changes_with_start_time(
self, mock_requests,
mock_create_config_job):
timestamp = '20140924140201'
self.drac_client.commit_pending_raid_changes('controller',
start_time=timestamp)
mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_RAIDService,
cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target='controller', reboot=False,
start_time=timestamp)
@mock.patch.object(dracclient.resources.job.JobManagement,
'create_config_job', spec_set=True, autospec=True)
def test_commit_pending_raid_changes_with_reboot_and_start_time(
self, mock_requests,
mock_create_config_job):
timestamp = '20140924140201'
self.drac_client.commit_pending_raid_changes('controller',
reboot=True,
start_time=timestamp)
mock_create_config_job.assert_called_once_with(
mock.ANY, resource_uri=uris.DCIM_RAIDService,
cim_creation_class_name='DCIM_RAIDService',
cim_name='DCIM:RAIDService', target='controller', reboot=True,
start_time=timestamp)
@mock.patch.object(dracclient.resources.job.JobManagement, @mock.patch.object(dracclient.resources.job.JobManagement,
'delete_pending_config', spec_set=True, autospec=True) 'delete_pending_config', spec_set=True, autospec=True)