add modify to snapshot policy (#59149)
This commit is contained in:
parent
f088621610
commit
48021a4200
2 changed files with 648 additions and 35 deletions
|
@ -20,11 +20,11 @@ extends_documentation_fragment:
|
||||||
version_added: '2.8'
|
version_added: '2.8'
|
||||||
author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
|
author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
|
||||||
description:
|
description:
|
||||||
- Create/Delete ONTAP snapshot policies
|
- Create/Modify/Delete ONTAP snapshot policies
|
||||||
options:
|
options:
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
- If you want to create or delete a snapshot policy.
|
- If you want to create, modify or delete a snapshot policy.
|
||||||
choices: ['present', 'absent']
|
choices: ['present', 'absent']
|
||||||
default: present
|
default: present
|
||||||
name:
|
name:
|
||||||
|
@ -46,41 +46,81 @@ options:
|
||||||
type: list
|
type: list
|
||||||
schedule:
|
schedule:
|
||||||
description:
|
description:
|
||||||
- schedule to be added inside the policy.
|
- Schedule to be added inside the policy.
|
||||||
type: list
|
type: list
|
||||||
|
snapmirror_label:
|
||||||
|
description:
|
||||||
|
- SnapMirror label assigned to each schedule inside the policy. Use an empty
|
||||||
|
string ('') for no label.
|
||||||
|
type: list
|
||||||
|
required: false
|
||||||
|
version_added: '2.9'
|
||||||
|
vserver:
|
||||||
|
description:
|
||||||
|
- The name of the vserver to use. In a multi-tenanted environment, assigning a
|
||||||
|
Snapshot Policy to a vserver will restrict its use to that vserver.
|
||||||
|
required: false
|
||||||
|
version_added: '2.9'
|
||||||
'''
|
'''
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
- name: create Snapshot policy
|
- name: Create Snapshot policy
|
||||||
na_ontap_snapshot_policy:
|
na_ontap_snapshot_policy:
|
||||||
state: present
|
state: present
|
||||||
name: ansible2
|
name: ansible2
|
||||||
schedule: hourly
|
schedule: hourly
|
||||||
count: 150
|
count: 150
|
||||||
enabled: True
|
enabled: True
|
||||||
username: "{{ netapp username }}"
|
username: "{{ netapp_username }}"
|
||||||
password: "{{ netapp password }}"
|
password: "{{ netapp_password }}"
|
||||||
hostname: "{{ netapp hostname }}"
|
hostname: "{{ netapp_hostname }}"
|
||||||
https: False
|
https: False
|
||||||
|
|
||||||
- name: Create Snapshot policy with multiple schedules
|
- name: Create Snapshot policy with multiple schedules
|
||||||
na_ontap_snapshot_policy:
|
na_ontap_snapshot_policy:
|
||||||
state: present
|
state: present
|
||||||
name: ansible2
|
name: ansible2
|
||||||
schedule: ['hourly', 'daily', 'weekly', monthly', '5min']
|
schedule: ['hourly', 'daily', 'weekly', 'monthly', '5min']
|
||||||
count: [1, 2, 3, 4, 5]
|
count: [1, 2, 3, 4, 5]
|
||||||
enabled: True
|
enabled: True
|
||||||
username: "{{ netapp username }}"
|
username: "{{ netapp_username }}"
|
||||||
password: "{{ netapp password }}"
|
password: "{{ netapp_password }}"
|
||||||
hostname: "{{ netapp hostname }}"
|
hostname: "{{ netapp_hostname }}"
|
||||||
https: False
|
https: False
|
||||||
|
|
||||||
- name: delete Snapshot policy
|
- name: Create Snapshot policy owned by a vserver
|
||||||
|
na_ontap_snapshot_policy:
|
||||||
|
state: present
|
||||||
|
name: ansible3
|
||||||
|
vserver: ansible
|
||||||
|
schedule: ['hourly', 'daily', 'weekly', 'monthly', '5min']
|
||||||
|
count: [1, 2, 3, 4, 5]
|
||||||
|
snapmirror_label: ['hourly', 'daily', 'weekly', 'monthly', '']
|
||||||
|
enabled: True
|
||||||
|
username: "{{ netapp_username }}"
|
||||||
|
password: "{{ netapp_password }}"
|
||||||
|
hostname: "{{ netapp_hostname }}"
|
||||||
|
https: False
|
||||||
|
|
||||||
|
- name: Modify Snapshot policy with multiple schedules
|
||||||
|
na_ontap_snapshot_policy:
|
||||||
|
state: present
|
||||||
|
name: ansible2
|
||||||
|
schedule: ['daily', 'weekly']
|
||||||
|
count: [20, 30]
|
||||||
|
snapmirror_label: ['daily', 'weekly']
|
||||||
|
enabled: True
|
||||||
|
username: "{{ netapp_username }}"
|
||||||
|
password: "{{ netapp_password }}"
|
||||||
|
hostname: "{{ netapp_hostname }}"
|
||||||
|
https: False
|
||||||
|
|
||||||
|
- name: Delete Snapshot policy
|
||||||
na_ontap_snapshot_policy:
|
na_ontap_snapshot_policy:
|
||||||
state: absent
|
state: absent
|
||||||
name: ansible2
|
name: ansible2
|
||||||
username: "{{ netapp username }}"
|
username: "{{ netapp_username }}"
|
||||||
password: "{{ netapp password }}"
|
password: "{{ netapp_password }}"
|
||||||
hostname: "{{ netapp hostname }}"
|
hostname: "{{ netapp_hostname }}"
|
||||||
https: False
|
https: False
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -111,7 +151,9 @@ class NetAppOntapSnapshotPolicy(object):
|
||||||
# count is a list of integers
|
# count is a list of integers
|
||||||
count=dict(required=False, type="list", elements="int"),
|
count=dict(required=False, type="list", elements="int"),
|
||||||
comment=dict(required=False, type="str"),
|
comment=dict(required=False, type="str"),
|
||||||
schedule=dict(required=False, type="list", elements="str")
|
schedule=dict(required=False, type="list", elements="str"),
|
||||||
|
snapmirror_label=dict(required=False, type="list", elements="str"),
|
||||||
|
vserver=dict(required=False, type="str")
|
||||||
))
|
))
|
||||||
self.module = AnsibleModule(
|
self.module = AnsibleModule(
|
||||||
argument_spec=self.argument_spec,
|
argument_spec=self.argument_spec,
|
||||||
|
@ -128,7 +170,10 @@ class NetAppOntapSnapshotPolicy(object):
|
||||||
self.module.fail_json(
|
self.module.fail_json(
|
||||||
msg="the python NetApp-Lib module is required")
|
msg="the python NetApp-Lib module is required")
|
||||||
else:
|
else:
|
||||||
self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
|
if 'vserver' in self.parameters:
|
||||||
|
self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
|
||||||
|
else:
|
||||||
|
self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
|
||||||
return
|
return
|
||||||
|
|
||||||
def get_snapshot_policy(self):
|
def get_snapshot_policy(self):
|
||||||
|
@ -141,13 +186,30 @@ class NetAppOntapSnapshotPolicy(object):
|
||||||
query = netapp_utils.zapi.NaElement("query")
|
query = netapp_utils.zapi.NaElement("query")
|
||||||
snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-policy-info")
|
snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-policy-info")
|
||||||
snapshot_info_obj.add_new_child("policy", self.parameters['name'])
|
snapshot_info_obj.add_new_child("policy", self.parameters['name'])
|
||||||
|
if 'vserver' in self.parameters:
|
||||||
|
snapshot_info_obj.add_new_child("vserver-name", self.parameters['vserver'])
|
||||||
query.add_child_elem(snapshot_info_obj)
|
query.add_child_elem(snapshot_info_obj)
|
||||||
snapshot_obj.add_child_elem(query)
|
snapshot_obj.add_child_elem(query)
|
||||||
try:
|
try:
|
||||||
result = self.server.invoke_successfully(snapshot_obj, True)
|
result = self.server.invoke_successfully(snapshot_obj, True)
|
||||||
if result.get_child_by_name('num-records') and \
|
if result.get_child_by_name('num-records') and \
|
||||||
int(result.get_child_content('num-records')) == 1:
|
int(result.get_child_content('num-records')) == 1:
|
||||||
return result
|
snapshot_policy = result.get_child_by_name('attributes-list').get_child_by_name('snapshot-policy-info')
|
||||||
|
current = {}
|
||||||
|
current['name'] = snapshot_policy.get_child_content('policy')
|
||||||
|
current['vserver'] = snapshot_policy.get_child_content('vserver-name')
|
||||||
|
current['enabled'] = False if snapshot_policy.get_child_content('enabled').lower() == 'false' else True
|
||||||
|
current['comment'] = snapshot_policy.get_child_content('comment') or ''
|
||||||
|
current['schedule'], current['count'], current['snapmirror_label'] = [], [], []
|
||||||
|
if snapshot_policy.get_child_by_name('snapshot-policy-schedules'):
|
||||||
|
for schedule in snapshot_policy['snapshot-policy-schedules'].get_children():
|
||||||
|
current['schedule'].append(schedule.get_child_content('schedule'))
|
||||||
|
current['count'].append(int(schedule.get_child_content('count')))
|
||||||
|
snapmirror_label = schedule.get_child_content('snapmirror-label')
|
||||||
|
if snapmirror_label is None or snapmirror_label == '-':
|
||||||
|
snapmirror_label = ''
|
||||||
|
current['snapmirror_label'].append(snapmirror_label)
|
||||||
|
return current
|
||||||
except netapp_utils.zapi.NaApiError as error:
|
except netapp_utils.zapi.NaApiError as error:
|
||||||
self.module.fail_json(msg=to_native(error), exception=traceback.format_exc())
|
self.module.fail_json(msg=to_native(error), exception=traceback.format_exc())
|
||||||
return None
|
return None
|
||||||
|
@ -157,10 +219,136 @@ class NetAppOntapSnapshotPolicy(object):
|
||||||
Validate if each schedule has a count associated
|
Validate if each schedule has a count associated
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
if len(self.parameters['count']) > 5 or len(self.parameters['schedule']) > 5 or \
|
if 'count' not in self.parameters or 'schedule' not in self.parameters or \
|
||||||
|
len(self.parameters['count']) > 5 or len(self.parameters['schedule']) > 5 or \
|
||||||
|
len(self.parameters['count']) < 1 or len(self.parameters['schedule']) < 1 or \
|
||||||
len(self.parameters['count']) != len(self.parameters['schedule']):
|
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,"
|
self.module.fail_json(msg="Error: A Snapshot policy must have at least 1 "
|
||||||
"and a count representing maximum number of Snapshot copies for each schedule")
|
"schedule and can have up to a maximum of 5 schedules, with a count "
|
||||||
|
"representing the maximum number of Snapshot copies for each schedule")
|
||||||
|
|
||||||
|
if 'snapmirror_label' in self.parameters:
|
||||||
|
if len(self.parameters['snapmirror_label']) != len(self.parameters['schedule']):
|
||||||
|
self.module.fail_json(msg="Error: Each Snapshot Policy schedule must have an "
|
||||||
|
"accompanying SnapMirror Label")
|
||||||
|
|
||||||
|
def modify_snapshot_policy(self, current):
|
||||||
|
"""
|
||||||
|
Modifies an existing snapshot policy
|
||||||
|
"""
|
||||||
|
# Set up required variables to modify snapshot policy
|
||||||
|
options = {'policy': self.parameters['name']}
|
||||||
|
modify = False
|
||||||
|
|
||||||
|
# Set up optional variables to modify snapshot policy
|
||||||
|
if 'enabled' in self.parameters and self.parameters['enabled'] != current['enabled']:
|
||||||
|
options['enabled'] = str(self.parameters['enabled'])
|
||||||
|
modify = True
|
||||||
|
if 'comment' in self.parameters and self.parameters['comment'] != current['comment']:
|
||||||
|
options['comment'] = self.parameters['comment']
|
||||||
|
modify = True
|
||||||
|
|
||||||
|
if modify:
|
||||||
|
snapshot_obj = netapp_utils.zapi.NaElement.create_node_with_children('snapshot-policy-modify', **options)
|
||||||
|
try:
|
||||||
|
self.server.invoke_successfully(snapshot_obj, True)
|
||||||
|
except netapp_utils.zapi.NaApiError as error:
|
||||||
|
self.module.fail_json(msg='Error modifying snapshot policy %s: %s' %
|
||||||
|
(self.parameters['name'], to_native(error)),
|
||||||
|
exception=traceback.format_exc())
|
||||||
|
|
||||||
|
def modify_snapshot_policy_schedules(self, current):
|
||||||
|
"""
|
||||||
|
Modify existing schedules in snapshot policy
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self.validate_parameters()
|
||||||
|
|
||||||
|
delete_schedules, modify_schedules, add_schedules = [], [], []
|
||||||
|
|
||||||
|
if 'snapmirror_label' in self.parameters:
|
||||||
|
snapmirror_labels = self.parameters['snapmirror_label']
|
||||||
|
else:
|
||||||
|
# User hasn't supplied any snapmirror labels.
|
||||||
|
snapmirror_labels = [None] * len(self.parameters['schedule'])
|
||||||
|
|
||||||
|
# Identify schedules for deletion
|
||||||
|
for schedule in current['schedule']:
|
||||||
|
schedule = schedule.strip()
|
||||||
|
if schedule not in [item.strip() for item in self.parameters['schedule']]:
|
||||||
|
options = {'policy': current['name'],
|
||||||
|
'schedule': schedule}
|
||||||
|
delete_schedules.append(options)
|
||||||
|
|
||||||
|
# Identify schedules to be modified or added
|
||||||
|
for schedule, count, snapmirror_label in zip(self.parameters['schedule'], self.parameters['count'], snapmirror_labels):
|
||||||
|
schedule = schedule.strip()
|
||||||
|
if snapmirror_label is not None:
|
||||||
|
snapmirror_label = snapmirror_label.strip()
|
||||||
|
|
||||||
|
options = {'policy': current['name'],
|
||||||
|
'schedule': schedule}
|
||||||
|
|
||||||
|
if schedule in current['schedule']:
|
||||||
|
# Schedule exists. Only modify if it has changed.
|
||||||
|
modify = False
|
||||||
|
schedule_index = current['schedule'].index(schedule)
|
||||||
|
|
||||||
|
if count != current['count'][schedule_index]:
|
||||||
|
options['new-count'] = str(count)
|
||||||
|
modify = True
|
||||||
|
|
||||||
|
if snapmirror_label is not None:
|
||||||
|
if snapmirror_label != current['snapmirror_label'][schedule_index]:
|
||||||
|
options['new-snapmirror-label'] = snapmirror_label
|
||||||
|
modify = True
|
||||||
|
|
||||||
|
if modify:
|
||||||
|
modify_schedules.append(options)
|
||||||
|
else:
|
||||||
|
# New schedule
|
||||||
|
options['count'] = str(count)
|
||||||
|
if snapmirror_label is not None and snapmirror_label != '':
|
||||||
|
options['snapmirror-label'] = snapmirror_label
|
||||||
|
add_schedules.append(options)
|
||||||
|
|
||||||
|
# Delete N-1 schedules no longer required. Must leave 1 schedule in policy
|
||||||
|
# at any one time. Delete last one afterwards.
|
||||||
|
while len(delete_schedules) > 1:
|
||||||
|
options = delete_schedules.pop()
|
||||||
|
self.modify_snapshot_policy_schedule(options, 'snapshot-policy-remove-schedule')
|
||||||
|
|
||||||
|
# Modify schedules.
|
||||||
|
while len(modify_schedules) > 0:
|
||||||
|
options = modify_schedules.pop()
|
||||||
|
self.modify_snapshot_policy_schedule(options, 'snapshot-policy-modify-schedule')
|
||||||
|
|
||||||
|
# Add N-1 new schedules. Add last one after last schedule has been deleted.
|
||||||
|
while len(add_schedules) > 1:
|
||||||
|
options = add_schedules.pop()
|
||||||
|
self.modify_snapshot_policy_schedule(options, 'snapshot-policy-add-schedule')
|
||||||
|
|
||||||
|
# Delete last schedule no longer required.
|
||||||
|
while len(delete_schedules) > 0:
|
||||||
|
options = delete_schedules.pop()
|
||||||
|
self.modify_snapshot_policy_schedule(options, 'snapshot-policy-remove-schedule')
|
||||||
|
|
||||||
|
# Add last new schedule.
|
||||||
|
while len(add_schedules) > 0:
|
||||||
|
options = add_schedules.pop()
|
||||||
|
self.modify_snapshot_policy_schedule(options, 'snapshot-policy-add-schedule')
|
||||||
|
|
||||||
|
def modify_snapshot_policy_schedule(self, options, zapi):
|
||||||
|
"""
|
||||||
|
Add, modify or remove a schedule to/from a snapshot policy
|
||||||
|
"""
|
||||||
|
snapshot_obj = netapp_utils.zapi.NaElement.create_node_with_children(zapi, **options)
|
||||||
|
try:
|
||||||
|
self.server.invoke_successfully(snapshot_obj, enable_tunneling=True)
|
||||||
|
except netapp_utils.zapi.NaApiError as error:
|
||||||
|
self.module.fail_json(msg='Error modifying snapshot policy schedule %s: %s' %
|
||||||
|
(self.parameters['name'], to_native(error)),
|
||||||
|
exception=traceback.format_exc())
|
||||||
|
|
||||||
def create_snapshot_policy(self):
|
def create_snapshot_policy(self):
|
||||||
"""
|
"""
|
||||||
|
@ -171,11 +359,23 @@ class NetAppOntapSnapshotPolicy(object):
|
||||||
options = {'policy': self.parameters['name'],
|
options = {'policy': self.parameters['name'],
|
||||||
'enabled': str(self.parameters['enabled']),
|
'enabled': str(self.parameters['enabled']),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if 'snapmirror_label' in self.parameters:
|
||||||
|
snapmirror_labels = self.parameters['snapmirror_label']
|
||||||
|
else:
|
||||||
|
# User hasn't supplied any snapmirror labels.
|
||||||
|
snapmirror_labels = [None] * len(self.parameters['schedule'])
|
||||||
|
|
||||||
# zapi attribute for first schedule is schedule1, second is schedule2 and so on
|
# 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)]
|
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):
|
for schedule, count, snapmirror_label, position in zip(self.parameters['schedule'], self.parameters['count'], snapmirror_labels, positions):
|
||||||
|
schedule = schedule.strip()
|
||||||
options['count' + position] = str(count)
|
options['count' + position] = str(count)
|
||||||
options['schedule' + position] = schedule
|
options['schedule' + position] = schedule
|
||||||
|
if snapmirror_label is not None:
|
||||||
|
snapmirror_label = snapmirror_label.strip()
|
||||||
|
if snapmirror_label != '':
|
||||||
|
options['snapmirror-label' + position] = snapmirror_label
|
||||||
snapshot_obj = netapp_utils.zapi.NaElement.create_node_with_children('snapshot-policy-create', **options)
|
snapshot_obj = netapp_utils.zapi.NaElement.create_node_with_children('snapshot-policy-create', **options)
|
||||||
|
|
||||||
# Set up optional variables to create a snapshot policy
|
# Set up optional variables to create a snapshot policy
|
||||||
|
@ -220,7 +420,13 @@ class NetAppOntapSnapshotPolicy(object):
|
||||||
"""
|
"""
|
||||||
self.asup_log_for_cserver("na_ontap_snapshot_policy")
|
self.asup_log_for_cserver("na_ontap_snapshot_policy")
|
||||||
current = self.get_snapshot_policy()
|
current = self.get_snapshot_policy()
|
||||||
|
modify = None
|
||||||
cd_action = self.na_helper.get_cd_action(current, self.parameters)
|
cd_action = self.na_helper.get_cd_action(current, self.parameters)
|
||||||
|
if cd_action is None and self.parameters['state'] == 'present':
|
||||||
|
# Don't sort schedule/count/snapmirror_label lists as it can
|
||||||
|
# mess up the intended parameter order.
|
||||||
|
modify = self.na_helper.get_modified_attributes(current, self.parameters)
|
||||||
|
|
||||||
if self.na_helper.changed:
|
if self.na_helper.changed:
|
||||||
if self.module.check_mode:
|
if self.module.check_mode:
|
||||||
pass
|
pass
|
||||||
|
@ -229,6 +435,9 @@ class NetAppOntapSnapshotPolicy(object):
|
||||||
self.create_snapshot_policy()
|
self.create_snapshot_policy()
|
||||||
elif cd_action == 'delete':
|
elif cd_action == 'delete':
|
||||||
self.delete_snapshot_policy()
|
self.delete_snapshot_policy()
|
||||||
|
if modify:
|
||||||
|
self.modify_snapshot_policy(current)
|
||||||
|
self.modify_snapshot_policy_schedules(current)
|
||||||
self.module.exit_json(changed=self.na_helper.changed)
|
self.module.exit_json(changed=self.na_helper.changed)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,16 @@ class MockONTAPConnection(object):
|
||||||
self.xml_in = xml
|
self.xml_in = xml
|
||||||
if self.type == 'policy':
|
if self.type == 'policy':
|
||||||
xml = self.build_snapshot_policy_info()
|
xml = self.build_snapshot_policy_info()
|
||||||
|
elif self.type == 'snapshot_policy_info_policy_disabled':
|
||||||
|
xml = self.build_snapshot_policy_info_policy_disabled()
|
||||||
|
elif self.type == 'snapshot_policy_info_comment_modified':
|
||||||
|
xml = self.build_snapshot_policy_info_comment_modified()
|
||||||
|
elif self.type == 'snapshot_policy_info_schedules_added':
|
||||||
|
xml = self.build_snapshot_policy_info_schedules_added()
|
||||||
|
elif self.type == 'snapshot_policy_info_schedules_deleted':
|
||||||
|
xml = self.build_snapshot_policy_info_schedules_deleted()
|
||||||
|
elif self.type == 'snapshot_policy_info_modified_schedule_counts':
|
||||||
|
xml = self.build_snapshot_policy_info_modified_schedule_counts()
|
||||||
elif self.type == 'policy_fail':
|
elif self.type == 'policy_fail':
|
||||||
raise netapp_utils.zapi.NaApiError(code='TEST', message="This exception is from the unit test")
|
raise netapp_utils.zapi.NaApiError(code='TEST', message="This exception is from the unit test")
|
||||||
self.xml_out = xml
|
self.xml_out = xml
|
||||||
|
@ -77,7 +87,170 @@ class MockONTAPConnection(object):
|
||||||
''' build xml data for snapshot-policy-info '''
|
''' build xml data for snapshot-policy-info '''
|
||||||
xml = netapp_utils.zapi.NaElement('xml')
|
xml = netapp_utils.zapi.NaElement('xml')
|
||||||
data = {'num-records': 1,
|
data = {'num-records': 1,
|
||||||
'attributes-list': {'snapshot-policy-info': {'policy': 'ansible'}}}
|
'attributes-list': {
|
||||||
|
'snapshot-policy-info': {
|
||||||
|
'comment': 'new comment',
|
||||||
|
'enabled': 'true',
|
||||||
|
'policy': 'ansible',
|
||||||
|
'snapshot-policy-schedules': {
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'count': 100,
|
||||||
|
'schedule': 'hourly',
|
||||||
|
'snapmirror-label': ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'vserver-name': 'hostname'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
xml.translate_struct(data)
|
||||||
|
return xml
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_snapshot_policy_info_comment_modified():
|
||||||
|
''' build xml data for snapshot-policy-info '''
|
||||||
|
xml = netapp_utils.zapi.NaElement('xml')
|
||||||
|
data = {'num-records': 1,
|
||||||
|
'attributes-list': {
|
||||||
|
'snapshot-policy-info': {
|
||||||
|
'comment': 'modified comment',
|
||||||
|
'enabled': 'true',
|
||||||
|
'policy': 'ansible',
|
||||||
|
'snapshot-policy-schedules': {
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'count': 100,
|
||||||
|
'schedule': 'hourly',
|
||||||
|
'snapmirror-label': ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'vserver-name': 'hostname'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
xml.translate_struct(data)
|
||||||
|
return xml
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_snapshot_policy_info_policy_disabled():
|
||||||
|
''' build xml data for snapshot-policy-info '''
|
||||||
|
xml = netapp_utils.zapi.NaElement('xml')
|
||||||
|
data = {'num-records': 1,
|
||||||
|
'attributes-list': {
|
||||||
|
'snapshot-policy-info': {
|
||||||
|
'comment': 'new comment',
|
||||||
|
'enabled': 'false',
|
||||||
|
'policy': 'ansible',
|
||||||
|
'snapshot-policy-schedules': {
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'count': 100,
|
||||||
|
'schedule': 'hourly',
|
||||||
|
'snapmirror-label': ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'vserver-name': 'hostname'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
xml.translate_struct(data)
|
||||||
|
return xml
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_snapshot_policy_info_schedules_added():
|
||||||
|
''' build xml data for snapshot-policy-info '''
|
||||||
|
xml = netapp_utils.zapi.NaElement('xml')
|
||||||
|
data = {'num-records': 1,
|
||||||
|
'attributes-list': {
|
||||||
|
'snapshot-policy-info': {
|
||||||
|
'comment': 'new comment',
|
||||||
|
'enabled': 'true',
|
||||||
|
'policy': 'ansible',
|
||||||
|
'snapshot-policy-schedules': [
|
||||||
|
{
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'count': 100,
|
||||||
|
'schedule': 'hourly',
|
||||||
|
'snapmirror-label': ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'count': 5,
|
||||||
|
'schedule': 'daily',
|
||||||
|
'snapmirror-label': 'daily'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'count': 10,
|
||||||
|
'schedule': 'weekly',
|
||||||
|
'snapmirror-label': ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'vserver-name': 'hostname'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
xml.translate_struct(data)
|
||||||
|
return xml
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_snapshot_policy_info_schedules_deleted():
|
||||||
|
''' build xml data for snapshot-policy-info '''
|
||||||
|
xml = netapp_utils.zapi.NaElement('xml')
|
||||||
|
data = {'num-records': 1,
|
||||||
|
'attributes-list': {
|
||||||
|
'snapshot-policy-info': {
|
||||||
|
'comment': 'new comment',
|
||||||
|
'enabled': 'true',
|
||||||
|
'policy': 'ansible',
|
||||||
|
'snapshot-policy-schedules': [
|
||||||
|
{
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'schedule': 'daily',
|
||||||
|
'count': 5,
|
||||||
|
'snapmirror-label': 'daily'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'vserver-name': 'hostname'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
xml.translate_struct(data)
|
||||||
|
return xml
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_snapshot_policy_info_modified_schedule_counts():
|
||||||
|
''' build xml data for snapshot-policy-info '''
|
||||||
|
xml = netapp_utils.zapi.NaElement('xml')
|
||||||
|
data = {'num-records': 1,
|
||||||
|
'attributes-list': {
|
||||||
|
'snapshot-policy-info': {
|
||||||
|
'comment': 'new comment',
|
||||||
|
'enabled': 'true',
|
||||||
|
'policy': 'ansible',
|
||||||
|
'snapshot-policy-schedules': [
|
||||||
|
{
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'count': 10,
|
||||||
|
'schedule': 'hourly',
|
||||||
|
'snapmirror-label': ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'count': 50,
|
||||||
|
'schedule': 'daily',
|
||||||
|
'snapmirror-label': 'daily'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'snapshot-schedule-info': {
|
||||||
|
'count': 100,
|
||||||
|
'schedule': 'weekly',
|
||||||
|
'snapmirror-label': ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'vserver-name': 'hostname'
|
||||||
|
}
|
||||||
|
}}
|
||||||
xml.translate_struct(data)
|
xml.translate_struct(data)
|
||||||
return xml
|
return xml
|
||||||
|
|
||||||
|
@ -124,6 +297,18 @@ class TestMyModule(unittest.TestCase):
|
||||||
'comment': comment
|
'comment': comment
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def set_default_current(self):
|
||||||
|
default_args = self.set_default_args()
|
||||||
|
return dict({
|
||||||
|
'name': default_args['name'],
|
||||||
|
'enabled': default_args['enabled'],
|
||||||
|
'count': [default_args['count']],
|
||||||
|
'schedule': [default_args['schedule']],
|
||||||
|
'snapmirror_label': [''],
|
||||||
|
'comment': default_args['comment'],
|
||||||
|
'vserver': default_args['hostname']
|
||||||
|
})
|
||||||
|
|
||||||
def test_module_fail_when_required_args_missing(self):
|
def test_module_fail_when_required_args_missing(self):
|
||||||
''' required arguments are reported as errors '''
|
''' required arguments are reported as errors '''
|
||||||
with pytest.raises(AnsibleFailJson) as exc:
|
with pytest.raises(AnsibleFailJson) as exc:
|
||||||
|
@ -166,20 +351,154 @@ class TestMyModule(unittest.TestCase):
|
||||||
my_obj.apply()
|
my_obj.apply()
|
||||||
assert not exc.value.args[0]['changed']
|
assert not exc.value.args[0]['changed']
|
||||||
|
|
||||||
def test_validate_params(self):
|
@patch('ansible.modules.storage.netapp.na_ontap_snapshot_policy.NetAppOntapSnapshotPolicy.modify_snapshot_policy')
|
||||||
|
def test_successful_modify_comment(self, modify_snapshot):
|
||||||
|
''' modifying snapshot policy comment and testing idempotency '''
|
||||||
data = self.set_default_args()
|
data = self.set_default_args()
|
||||||
data['schedule'] = ['s1', 's2']
|
data['comment'] = 'modified comment'
|
||||||
data['count'] = [1, 2, 3]
|
|
||||||
set_module_args(data)
|
set_module_args(data)
|
||||||
my_obj = my_module()
|
my_obj = my_module()
|
||||||
my_obj.asup_log_for_cserver = Mock(return_value=None)
|
my_obj.asup_log_for_cserver = Mock(return_value=None)
|
||||||
if not self.onbox:
|
if not self.onbox:
|
||||||
my_obj.server = self.server
|
my_obj.server = MockONTAPConnection('policy')
|
||||||
with pytest.raises(AnsibleFailJson) as exc:
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
my_obj.create_snapshot_policy()
|
my_obj.apply()
|
||||||
msg = 'Error: A Snapshot policy can have up to a maximum of 5 schedules,and a ' \
|
assert exc.value.args[0]['changed']
|
||||||
'count representing maximum number of Snapshot copies for each schedule'
|
current = self.set_default_current()
|
||||||
assert exc.value.args[0]['msg'] == msg
|
modify_snapshot.assert_called_with(current)
|
||||||
|
# to reset na_helper from remembering the previous 'changed' value
|
||||||
|
my_obj = my_module()
|
||||||
|
my_obj.asup_log_for_cserver = Mock(return_value=None)
|
||||||
|
if not self.onbox:
|
||||||
|
my_obj.server = MockONTAPConnection('snapshot_policy_info_comment_modified')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert not exc.value.args[0]['changed']
|
||||||
|
|
||||||
|
@patch('ansible.modules.storage.netapp.na_ontap_snapshot_policy.NetAppOntapSnapshotPolicy.modify_snapshot_policy')
|
||||||
|
def test_successful_disable_policy(self, modify_snapshot):
|
||||||
|
''' disabling snapshot policy and testing idempotency '''
|
||||||
|
data = self.set_default_args()
|
||||||
|
data['enabled'] = False
|
||||||
|
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 = MockONTAPConnection('policy')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert exc.value.args[0]['changed']
|
||||||
|
current = self.set_default_current()
|
||||||
|
modify_snapshot.assert_called_with(current)
|
||||||
|
# to reset na_helper from remembering the previous 'changed' value
|
||||||
|
my_obj = my_module()
|
||||||
|
my_obj.asup_log_for_cserver = Mock(return_value=None)
|
||||||
|
if not self.onbox:
|
||||||
|
my_obj.server = MockONTAPConnection('snapshot_policy_info_policy_disabled')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert not exc.value.args[0]['changed']
|
||||||
|
|
||||||
|
@patch('ansible.modules.storage.netapp.na_ontap_snapshot_policy.NetAppOntapSnapshotPolicy.modify_snapshot_policy')
|
||||||
|
def test_successful_enable_policy(self, modify_snapshot):
|
||||||
|
''' enabling snapshot policy and testing idempotency '''
|
||||||
|
data = self.set_default_args()
|
||||||
|
data['enabled'] = True
|
||||||
|
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 = MockONTAPConnection('snapshot_policy_info_policy_disabled')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert exc.value.args[0]['changed']
|
||||||
|
current = self.set_default_current()
|
||||||
|
current['enabled'] = False
|
||||||
|
modify_snapshot.assert_called_with(current)
|
||||||
|
# to reset na_helper from remembering the previous 'changed' value
|
||||||
|
my_obj = my_module()
|
||||||
|
my_obj.asup_log_for_cserver = Mock(return_value=None)
|
||||||
|
if not self.onbox:
|
||||||
|
my_obj.server = MockONTAPConnection('policy')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert not exc.value.args[0]['changed']
|
||||||
|
|
||||||
|
@patch('ansible.modules.storage.netapp.na_ontap_snapshot_policy.NetAppOntapSnapshotPolicy.modify_snapshot_policy')
|
||||||
|
def test_successful_modify_schedules_add(self, modify_snapshot):
|
||||||
|
''' adding snapshot policy schedules and testing idempotency '''
|
||||||
|
data = self.set_default_args()
|
||||||
|
data['schedule'] = ['hourly', 'daily', 'weekly']
|
||||||
|
data['count'] = [100, 5, 10]
|
||||||
|
data['snapmirror_label'] = ['', 'daily', '']
|
||||||
|
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 = MockONTAPConnection('policy')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert exc.value.args[0]['changed']
|
||||||
|
current = self.set_default_current()
|
||||||
|
modify_snapshot.assert_called_with(current)
|
||||||
|
# to reset na_helper from remembering the previous 'changed' value
|
||||||
|
my_obj = my_module()
|
||||||
|
my_obj.asup_log_for_cserver = Mock(return_value=None)
|
||||||
|
if not self.onbox:
|
||||||
|
my_obj.server = MockONTAPConnection('snapshot_policy_info_schedules_added')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert not exc.value.args[0]['changed']
|
||||||
|
|
||||||
|
@patch('ansible.modules.storage.netapp.na_ontap_snapshot_policy.NetAppOntapSnapshotPolicy.modify_snapshot_policy')
|
||||||
|
def test_successful_modify_schedules_delete(self, modify_snapshot):
|
||||||
|
''' deleting snapshot policy schedules and testing idempotency '''
|
||||||
|
data = self.set_default_args()
|
||||||
|
data['schedule'] = ['daily']
|
||||||
|
data['count'] = [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 = MockONTAPConnection('policy')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert exc.value.args[0]['changed']
|
||||||
|
current = self.set_default_current()
|
||||||
|
modify_snapshot.assert_called_with(current)
|
||||||
|
# to reset na_helper from remembering the previous 'changed' value
|
||||||
|
my_obj = my_module()
|
||||||
|
my_obj.asup_log_for_cserver = Mock(return_value=None)
|
||||||
|
if not self.onbox:
|
||||||
|
my_obj.server = MockONTAPConnection('snapshot_policy_info_schedules_deleted')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert not exc.value.args[0]['changed']
|
||||||
|
|
||||||
|
@patch('ansible.modules.storage.netapp.na_ontap_snapshot_policy.NetAppOntapSnapshotPolicy.modify_snapshot_policy')
|
||||||
|
def test_successful_modify_schedules(self, modify_snapshot):
|
||||||
|
''' modifying snapshot policy schedule counts and testing idempotency '''
|
||||||
|
data = self.set_default_args()
|
||||||
|
data['schedule'] = ['hourly', 'daily', 'weekly']
|
||||||
|
data['count'] = [10, 50, 100]
|
||||||
|
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 = MockONTAPConnection('policy')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert exc.value.args[0]['changed']
|
||||||
|
current = self.set_default_current()
|
||||||
|
modify_snapshot.assert_called_with(current)
|
||||||
|
# to reset na_helper from remembering the previous 'changed' value
|
||||||
|
my_obj = my_module()
|
||||||
|
my_obj.asup_log_for_cserver = Mock(return_value=None)
|
||||||
|
if not self.onbox:
|
||||||
|
my_obj.server = MockONTAPConnection('snapshot_policy_info_modified_schedule_counts')
|
||||||
|
with pytest.raises(AnsibleExitJson) as exc:
|
||||||
|
my_obj.apply()
|
||||||
|
assert not exc.value.args[0]['changed']
|
||||||
|
|
||||||
@patch('ansible.modules.storage.netapp.na_ontap_snapshot_policy.NetAppOntapSnapshotPolicy.delete_snapshot_policy')
|
@patch('ansible.modules.storage.netapp.na_ontap_snapshot_policy.NetAppOntapSnapshotPolicy.delete_snapshot_policy')
|
||||||
def test_successful_delete(self, delete_snapshot):
|
def test_successful_delete(self, delete_snapshot):
|
||||||
|
@ -205,7 +524,7 @@ class TestMyModule(unittest.TestCase):
|
||||||
assert not exc.value.args[0]['changed']
|
assert not exc.value.args[0]['changed']
|
||||||
|
|
||||||
def test_valid_schedule_count(self):
|
def test_valid_schedule_count(self):
|
||||||
''' validate error when schedule has more than 5 elements '''
|
''' validate when schedule has same number of elements '''
|
||||||
data = self.set_default_args()
|
data = self.set_default_args()
|
||||||
data['schedule'] = ['hourly', 'daily', 'weekly', 'monthly', '5min']
|
data['schedule'] = ['hourly', 'daily', 'weekly', 'monthly', '5min']
|
||||||
data['count'] = [1, 2, 3, 4, 5]
|
data['count'] = [1, 2, 3, 4, 5]
|
||||||
|
@ -219,6 +538,40 @@ class TestMyModule(unittest.TestCase):
|
||||||
assert data['count'][2] == int(create_xml['count3'])
|
assert data['count'][2] == int(create_xml['count3'])
|
||||||
assert data['schedule'][4] == create_xml['schedule5']
|
assert data['schedule'][4] == create_xml['schedule5']
|
||||||
|
|
||||||
|
def test_valid_schedule_count_with_snapmirror_labels(self):
|
||||||
|
''' validate when schedule has same number of elements with snapmirror labels '''
|
||||||
|
data = self.set_default_args()
|
||||||
|
data['schedule'] = ['hourly', 'daily', 'weekly', 'monthly', '5min']
|
||||||
|
data['count'] = [1, 2, 3, 4, 5]
|
||||||
|
data['snapmirror_label'] = ['hourly', 'daily', 'weekly', 'monthly', '5min']
|
||||||
|
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']
|
||||||
|
assert data['snapmirror_label'][3] == create_xml['snapmirror-label4']
|
||||||
|
|
||||||
|
def test_invalid_params(self):
|
||||||
|
''' validate error when schedule does not have same number of elements '''
|
||||||
|
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 must have at least 1 ' \
|
||||||
|
'schedule and can have up to a maximum of 5 schedules, with a count ' \
|
||||||
|
'representing the maximum number of Snapshot copies for each schedule'
|
||||||
|
assert exc.value.args[0]['msg'] == msg
|
||||||
|
|
||||||
def test_invalid_schedule_count(self):
|
def test_invalid_schedule_count(self):
|
||||||
''' validate error when schedule has more than 5 elements '''
|
''' validate error when schedule has more than 5 elements '''
|
||||||
data = self.set_default_args()
|
data = self.set_default_args()
|
||||||
|
@ -231,8 +584,59 @@ class TestMyModule(unittest.TestCase):
|
||||||
my_obj.server = self.server
|
my_obj.server = self.server
|
||||||
with pytest.raises(AnsibleFailJson) as exc:
|
with pytest.raises(AnsibleFailJson) as exc:
|
||||||
my_obj.create_snapshot_policy()
|
my_obj.create_snapshot_policy()
|
||||||
msg = 'Error: A Snapshot policy can have up to a maximum of 5 schedules,and a ' \
|
msg = 'Error: A Snapshot policy must have at least 1 ' \
|
||||||
'count representing maximum number of Snapshot copies for each schedule'
|
'schedule and can have up to a maximum of 5 schedules, with a count ' \
|
||||||
|
'representing the maximum number of Snapshot copies for each schedule'
|
||||||
|
assert exc.value.args[0]['msg'] == msg
|
||||||
|
|
||||||
|
def test_invalid_schedule_count_less_than_one(self):
|
||||||
|
''' validate error when schedule has less than 1 element '''
|
||||||
|
data = self.set_default_args()
|
||||||
|
data['schedule'] = []
|
||||||
|
data['count'] = []
|
||||||
|
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 must have at least 1 ' \
|
||||||
|
'schedule and can have up to a maximum of 5 schedules, with a count ' \
|
||||||
|
'representing the maximum number of Snapshot copies for each schedule'
|
||||||
|
assert exc.value.args[0]['msg'] == msg
|
||||||
|
|
||||||
|
def test_invalid_schedule_count_is_none(self):
|
||||||
|
''' validate error when schedule is None '''
|
||||||
|
data = self.set_default_args()
|
||||||
|
data['schedule'] = None
|
||||||
|
data['count'] = None
|
||||||
|
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 must have at least 1 ' \
|
||||||
|
'schedule and can have up to a maximum of 5 schedules, with a count ' \
|
||||||
|
'representing the maximum number of Snapshot copies for each schedule'
|
||||||
|
assert exc.value.args[0]['msg'] == msg
|
||||||
|
|
||||||
|
def test_invalid_schedule_count_with_snapmirror_labels(self):
|
||||||
|
''' validate error when schedule with snapmirror labels does not have same number of elements '''
|
||||||
|
data = self.set_default_args()
|
||||||
|
data['schedule'] = ['s1', 's2', 's3']
|
||||||
|
data['count'] = [1, 2, 3]
|
||||||
|
data['snapmirror_label'] = ['sm1', 'sm2']
|
||||||
|
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: Each Snapshot Policy schedule must have an accompanying SnapMirror Label'
|
||||||
assert exc.value.args[0]['msg'] == msg
|
assert exc.value.args[0]['msg'] == msg
|
||||||
|
|
||||||
def test_if_all_methods_catch_exception(self):
|
def test_if_all_methods_catch_exception(self):
|
||||||
|
|
Loading…
Reference in a new issue