diff --git a/hpe3parclient/client.py b/hpe3parclient/client.py index 6b49315b..ffeb5dcb 100644 --- a/hpe3parclient/client.py +++ b/hpe3parclient/client.py @@ -4439,3 +4439,149 @@ def targetInRemoteCopyGroupExists( except Exception: pass return False + + def check_response(self, resp): + for r in resp: + if 'error' in str.lower(r) or 'invalid' in str.lower(r): + err_resp = r.strip() + return err_resp + + def createSchedule(self, schedule_name, task, taskfreq): + """Create Schedule for volume snapshot. + :param schedule_name - The name of the schedule + :type - string + :param task - command to for which schedule is created + :type - string + :param taskfreq - frequency of schedule + :type - string + """ + cmd = ['createsched'] + cmd.append("\"" + task + "\"") + if '@' not in taskfreq: + cmd.append("\"" + taskfreq + "\"") + else: + cmd.append(taskfreq) + cmd.append(schedule_name) + try: + resp = self._run(cmd) + + err_resp = self.check_response(resp) + if err_resp: + raise exceptions.SSHException(err_resp) + else: + for r in resp: + if str.lower('The schedule format is \ + or by @hourly @daily @monthly @weekly @monthly \ +@yearly') in str.lower(r): + raise exceptions.SSHException(r.strip()) + except exceptions.SSHException as ex: + raise exceptions.SSHException(ex) + + def deleteSchedule(self, schedule_name): + """Delete Schedule + :param schedule_name - The name of the schedule to delete + :type - string + """ + cmd = ['removesched', '-f', schedule_name] + try: + resp = self._run(cmd) + + err_resp = self.check_response(resp) + if err_resp: + err = (("Delete snapschedule failed Error is\ + '%(err_resp)s' ") % {'err_resp': err_resp}) + raise exceptions.SSHException(reason=err) + except exceptions.SSHException as ex: + raise exceptions.SSHException(reason=ex) + + def getSchedule(self, schedule_name): + """Get Schedule + :param schedule_name - The name of the schedule to get information + :type - string + """ + cmd = ['showsched ', schedule_name] + try: + result = self._run(cmd) + for r in result: + if 'No scheduled tasks ' in r: + msg = "Couldn't find the schedule '%s'" % schedule_name + raise exceptions.SSHNotFoundException(msg) + except exceptions.SSHNotFoundException as ex: + raise exceptions.SSHNotFoundException(ex) + return result + + def modifySchedule(self, name, schedule_opt): + """Modify Schedule. + :param name - The name of the schedule + :type - string + :param schedule_opt - + :type schedule_opt - dictionary of option to be modified + .. code-block:: python + + mod_request = { + 'newName': 'myNewName', # New name of the schedule + 'taskFrequency': '0 * * * *' # String containing cron or + # @monthly, @hourly, @daily, + # @yearly and @weekly. + } + """ + + cmd = ['setsched'] + if 'newName' in schedule_opt: + cmd.append('-name') + cmd.append(schedule_opt['newName']) + + if 'taskFrequency' in schedule_opt: + cmd.append('-s') + if '@' not in schedule_opt['taskFrequency']: + cmd.append("\"" + schedule_opt['taskFrequency'] + "\"") + else: + cmd.append(schedule_opt['taskFrequency']) + cmd.append(name) + try: + resp = self._run(cmd) + + err_resp = self.check_response(resp) + if err_resp: + raise exceptions.SSHException(err_resp) + else: + for r in resp: + if str.lower('The schedule format is \ + or by @hourly @daily @monthly @weekly @monthly \ +@yearly') in str.lower(r): + raise exceptions.SSHException(r.strip()) + + except exceptions.SSHException as ex: + raise exceptions.SSHException(ex) + + def suspendSchedule(self, schedule_name): + """Suspend Schedule + :param schedule_name - The name of the schedule to get information + :type - string + """ + cmd = ['setsched', '-suspend', schedule_name] + try: + resp = self._run(cmd) + err_resp = self.check_response(resp) + if err_resp: + err = (("Schedule suspend failed Error is\ + '%(err_resp)s' ") % {'err_resp': err_resp}) + raise exceptions.SSHException(reason=err) + except exceptions.SSHException as ex: + raise exceptions.SSHException(reason=ex) + + def resumeSchedule(self, schedule_name): + """Resume Schedule + :param schedule_name - The name of the schedule to get information + :type - string + """ + cmd = ['setsched', '-resume', schedule_name] + try: + resp = self._run(cmd) + err_resp = self.check_response(resp) + if err_resp: + err = (("Schedule resume failed Error is\ + '%(err_resp)s' ") % {'err_resp': err_resp}) + raise exceptions.SSHException(reason=err) + except exceptions.SSHException as ex: + raise exceptions.SSHException(reason=ex) diff --git a/hpe3parclient/exceptions.py b/hpe3parclient/exceptions.py index c6ff662c..b8aad46c 100644 --- a/hpe3parclient/exceptions.py +++ b/hpe3parclient/exceptions.py @@ -472,6 +472,10 @@ class SrstatldException(SSHException): message = "SSH command failed: %(command)s" +class SSHNotFoundException(SSHException): + message = "SSH command failed: %(command)s" + + class ProcessExecutionError(Exception): def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, description=None): diff --git a/test/test_HPE3ParClient_volume.py b/test/test_HPE3ParClient_volume.py index 6b6dbea1..e797ebaa 100644 --- a/test/test_HPE3ParClient_volume.py +++ b/test/test_HPE3ParClient_volume.py @@ -17,7 +17,7 @@ import time import unittest from testconfig import config - +import mock from test import HPE3ParClient_base as hpe3parbase from hpe3parclient import exceptions @@ -29,6 +29,8 @@ VOLUME_NAME3 = 'VOLUME3_UNIT_TEST' + hpe3parbase.TIME SNAP_NAME1 = 'SNAP_UNIT_TEST1' + hpe3parbase.TIME SNAP_NAME2 = 'SNAP_UNIT_TEST2' + hpe3parbase.TIME +SCHEDULE_NAME1 = 'SCHEDULE_NAME1' + hpe3parbase.TIME +SCHEDULE_NAME2 = 'SCHEDULE_NAME2' + hpe3parbase.TIME DOMAIN = 'UNIT_TEST_DOMAIN' VOLUME_SET_NAME1 = 'VOLUME_SET1_UNIT_TEST' + hpe3parbase.TIME VOLUME_SET_NAME2 = 'VOLUME_SET2_UNIT_TEST' + hpe3parbase.TIME @@ -2189,6 +2191,68 @@ def test_25_promote_vcopy_on_rep_vol_with_bad_param(self): self.printFooter('promote_vcopy_on_rep_vol_with_bad_param') + @mock.patch('hpe3parclient.client.HPE3ParClient._run') + @mock.patch('hpe3parclient.client.HPE3ParClient.check_response') + def test_create_schedule(self, mock_res, mock_run): + self.printHeader('schedule_test') + mock_run.return_value = "SchedName File/Command Min Hour DOM Month DOW CreatedBy Status Alert NextRunTim\ +schedule1 createsv svro-vol@h@@m@ test_volume 0* * * * 3paradm active Y 2" + mock_res.return_value = None + + cmd = "createsv -ro snap-"+VOLUME_NAME1+" "+VOLUME_NAME1 + self.cl.createSchedule(SCHEDULE_NAME1,cmd,'hourly') + res = self.cl.getSchedule(SCHEDULE_NAME1) + self.assertIsNotNone(res) + self.printFooter('create_schedule') + + @mock.patch('hpe3parclient.client.HPE3ParClient._run') + @mock.patch('hpe3parclient.client.HPE3ParClient.check_response') + def test_delete_schedule(self, mock_res, mock_run): + self.printHeader('delete_schedule') + mock_run.return_value = "SchedName File/Command Min Hour DOM Month DOW CreatedBy Status Alert NextRunTim\ +schedule1 createsv svro-vol@h@@m@ test_volume 0* * * * 3paradm active Y 2" + mock_res.return_value = None + + cmd = "createsv -ro snap-"+VOLUME_NAME1+" "+VOLUME_NAME1 + self.cl.createSchedule(SCHEDULE_NAME1,cmd,'hourly') + res = self.cl.getSchedule(SCHEDULE_NAME1) + self.assertIsNotNone(res) + mock_run.return_value = 'No scheduled tasks' + self.cl.deleteSchedule(SCHEDULE_NAME1) + res = self.cl.getSchedule(SCHEDULE_NAME1) + self.assertEqual(res, 'No scheduled tasks') + self.printFooter('delete_schedule') + + @mock.patch('hpe3parclient.client.HPE3ParClient._run') + @mock.patch('hpe3parclient.client.HPE3ParClient.check_response') + def test_modify_schedule(self, mock_res, mock_run): + self.printHeader('modify_schedule') + mock_run.return_value = "SchedName File/Command Min Hour DOM Month DOW CreatedBy Status Alert NextRunTim\ +schedule1 createsv svro-vol@h@@m@ test_volume 0* * * * 3paradm active Y 2" + mock_res.return_value = None + + cmd = "createsv -ro snap-"+VOLUME_NAME1+" "+VOLUME_NAME1 + self.cl.createSchedule(SCHEDULE_NAME1,cmd,'hourly') + self.cl.modifySchedule(SCHEDULE_NAME1, {'newName': SCHEDULE_NAME2}) + res = self.cl.getSchedule(SCHEDULE_NAME2) + self.assertIsNotNone(res) + self.printFooter('modify_schedule') + + @mock.patch('hpe3parclient.client.HPE3ParClient._run') + @mock.patch('hpe3parclient.client.HPE3ParClient.check_response') + def test_suspend_resume_schedule(self, mock_res, mock_run): + self.printHeader('suspend_resume_schedule') + mock_run.return_value = "SchedName File/Command Min Hour DOM Month DOW CreatedBy Status Alert NextRunTim\ +schedule1 createsv svro-vol@h@@m@ test_volume 0* * * * 3paradm active Y 2" + mock_res.return_value = None + + cmd = "createsv -ro snap-"+VOLUME_NAME1+" "+VOLUME_NAME1 + self.cl.createSchedule(SCHEDULE_NAME1,cmd,'hourly') + self.cl.suspendSchedule(SCHEDULE_NAME1) + self.cl.resumeSchedule(SCHEDULE_NAME1) + self.printFooter('suspend_resume_schedule') + + # testing # suite = unittest.TestLoader(). # loadTestsFromTestCase(HPE3ParClientVolumeTestCase)