From a58570f1bc828b0136f1a7b4014986e2cca57d23 Mon Sep 17 00:00:00 2001 From: Chris Archibald Date: Mon, 10 Jun 2019 00:24:26 -0700 Subject: [PATCH] na_ontap_snapshot_policy: Add ability to multiple schedules (#57366) --- .../netapp/na_ontap_snapshot_policy.py | 38 +++++++++++++-- .../netapp/test_na_ontap_snapshot_policy.py | 46 +++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/lib/ansible/modules/storage/netapp/na_ontap_snapshot_policy.py b/lib/ansible/modules/storage/netapp/na_ontap_snapshot_policy.py index 83f695f652f..0af381c56f5 100644 --- a/lib/ansible/modules/storage/netapp/na_ontap_snapshot_policy.py +++ b/lib/ansible/modules/storage/netapp/na_ontap_snapshot_policy.py @@ -43,10 +43,11 @@ options: count: description: Retention count for the snapshots created by the schedule. - type: int + type: list schedule: description: - schedule to be added inside the policy. + type: list ''' EXAMPLES = """ - name: create Snapshot policy @@ -61,6 +62,18 @@ EXAMPLES = """ hostname: "{{ netapp hostname }}" https: False + - name: Create Snapshot policy with multiple schedules + na_ontap_snapshot_policy: + state: present + name: ansible2 + schedule: ['hourly', 'daily', 'weekly', monthly', '5min'] + count: [1, 2, 3, 4, 5] + enabled: True + username: "{{ netapp username }}" + password: "{{ netapp password }}" + hostname: "{{ netapp hostname }}" + https: False + - name: delete Snapshot policy na_ontap_snapshot_policy: state: absent @@ -95,9 +108,10 @@ class NetAppOntapSnapshotPolicy(object): 'present', 'absent'], default='present'), name=dict(required=True, type="str"), enabled=dict(required=False, type="bool"), - count=dict(required=False, type="int"), + # count is a list of integers + count=dict(required=False, type="list", elements="int"), comment=dict(required=False, type="str"), - schedule=dict(required=False, type="str") + schedule=dict(required=False, type="list", elements="str") )) self.module = AnsibleModule( argument_spec=self.argument_spec, @@ -138,16 +152,30 @@ class NetAppOntapSnapshotPolicy(object): self.module.fail_json(msg=to_native(error), exception=traceback.format_exc()) return None + def validate_parameters(self): + """ + Validate if each schedule has a count associated + :return: None + """ + if len(self.parameters['count']) > 5 or len(self.parameters['schedule']) > 5 or \ + len(self.parameters['count']) != len(self.parameters['schedule']): + self.module.fail_json(msg="Error: A Snapshot policy can have up to a maximum of 5 schedules," + "and a count representing maximum number of Snapshot copies for each schedule") + def create_snapshot_policy(self): """ Creates a new snapshot policy """ # set up required variables to create a snapshot policy + self.validate_parameters() options = {'policy': self.parameters['name'], 'enabled': str(self.parameters['enabled']), - 'count1': str(self.parameters['count']), - 'schedule1': self.parameters['schedule'] } + # zapi attribute for first schedule is schedule1, second is schedule2 and so on + positions = [str(i) for i in range(1, len(self.parameters['schedule']) + 1)] + for schedule, count, position in zip(self.parameters['schedule'], self.parameters['count'], positions): + options['count' + position] = str(count) + options['schedule' + position] = schedule snapshot_obj = netapp_utils.zapi.NaElement.create_node_with_children('snapshot-policy-create', **options) # Set up optional variables to create a snapshot policy diff --git a/test/units/modules/storage/netapp/test_na_ontap_snapshot_policy.py b/test/units/modules/storage/netapp/test_na_ontap_snapshot_policy.py index dcb7367172b..5d4a015c7d5 100644 --- a/test/units/modules/storage/netapp/test_na_ontap_snapshot_policy.py +++ b/test/units/modules/storage/netapp/test_na_ontap_snapshot_policy.py @@ -166,6 +166,21 @@ class TestMyModule(unittest.TestCase): my_obj.apply() assert not exc.value.args[0]['changed'] + def test_validate_params(self): + data = self.set_default_args() + data['schedule'] = ['s1', 's2'] + data['count'] = [1, 2, 3] + set_module_args(data) + my_obj = my_module() + my_obj.asup_log_for_cserver = Mock(return_value=None) + if not self.onbox: + my_obj.server = self.server + with pytest.raises(AnsibleFailJson) as exc: + my_obj.create_snapshot_policy() + msg = 'Error: A Snapshot policy can have up to a maximum of 5 schedules,and a ' \ + 'count representing maximum number of Snapshot copies for each schedule' + assert exc.value.args[0]['msg'] == msg + @patch('ansible.modules.storage.netapp.na_ontap_snapshot_policy.NetAppOntapSnapshotPolicy.delete_snapshot_policy') def test_successful_delete(self, delete_snapshot): ''' deleting snapshot policy and testing idempotency ''' @@ -189,6 +204,37 @@ class TestMyModule(unittest.TestCase): my_obj.apply() assert not exc.value.args[0]['changed'] + def test_valid_schedule_count(self): + ''' validate error when schedule has more than 5 elements ''' + data = self.set_default_args() + data['schedule'] = ['hourly', 'daily', 'weekly', 'monthly', '5min'] + data['count'] = [1, 2, 3, 4, 5] + set_module_args(data) + my_obj = my_module() + my_obj.asup_log_for_cserver = Mock(return_value=None) + if not self.onbox: + my_obj.server = self.server + my_obj.create_snapshot_policy() + create_xml = my_obj.server.xml_in + assert data['count'][2] == int(create_xml['count3']) + assert data['schedule'][4] == create_xml['schedule5'] + + def test_invalid_schedule_count(self): + ''' validate error when schedule has more than 5 elements ''' + data = self.set_default_args() + data['schedule'] = ['s1', 's2', 's3', 's4', 's5', 's6'] + data['count'] = [1, 2, 3, 4, 5, 6] + set_module_args(data) + my_obj = my_module() + my_obj.asup_log_for_cserver = Mock(return_value=None) + if not self.onbox: + my_obj.server = self.server + with pytest.raises(AnsibleFailJson) as exc: + my_obj.create_snapshot_policy() + msg = 'Error: A Snapshot policy can have up to a maximum of 5 schedules,and a ' \ + 'count representing maximum number of Snapshot copies for each schedule' + assert exc.value.args[0]['msg'] == msg + def test_if_all_methods_catch_exception(self): module_args = {} module_args.update(self.set_default_args())