summaryrefslogtreecommitdiff
path: root/lib/ansible/modules
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/modules')
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_aggregate.py474
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_autosupport.py275
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain.py436
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain_ports.py215
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_cg_snapshot.py219
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_cifs.py306
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_cifs_acl.py238
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_cifs_server.py329
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_cluster.py287
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_cluster_ha.py133
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_cluster_peer.py295
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_command.py228
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_disks.py205
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_dns.py294
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_export_policy.py231
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_export_policy_rule.py431
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_fcp.py210
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_firewall_policy.py351
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_firmware_upgrade.py461
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_flexcache.py474
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_igroup.py346
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_igroup_initiator.py183
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_info.py619
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_interface.py449
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_ipspace.py258
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_iscsi.py272
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_job_schedule.py297
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_kerberos_realm.py318
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_ldap.py228
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_ldap_client.py359
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_license.py326
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_lun.py406
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_lun_copy.py182
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_lun_map.py282
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_motd.py209
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_ndmp.py342
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_net_ifgrp.py307
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_net_port.py226
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_net_routes.py324
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_net_subnet.py326
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_net_vlan.py186
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_nfs.py576
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_node.py144
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_ntp.py226
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_nvme.py209
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_nvme_namespace.py195
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_nvme_subsystem.py355
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_object_store.py237
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_ports.py380
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_portset.py278
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_qos_adaptive_policy_group.py335
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_qos_policy_group.py290
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_qtree.py303
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_quotas.py345
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_security_key_manager.py229
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_service_processor_network.py284
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_snapmirror.py716
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_snapshot.py326
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_snapshot_policy.py453
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_snmp.py152
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_software_update.py301
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_svm.py444
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_svm_options.py156
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_ucadapter.py224
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_unix_group.py348
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_unix_user.py253
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_user.py389
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_user_role.py268
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_volume.py1283
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_volume_autosize.py361
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_volume_clone.py228
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_vscan.py178
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_vscan_on_access_policy.py366
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_vscan_on_demand_task.py313
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_vscan_scanner_pool.py240
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_vserver_cifs_security.py282
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_vserver_peer.py276
77 files changed, 0 insertions, 24480 deletions
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_aggregate.py b/lib/ansible/modules/storage/netapp/na_ontap_aggregate.py
deleted file mode 100644
index ac76e77abd..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_aggregate.py
+++ /dev/null
@@ -1,474 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_aggregate
-short_description: NetApp ONTAP manage aggregates.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create, delete, or manage aggregates on ONTAP.
-
-options:
-
- state:
- description:
- - Whether the specified aggregate should exist or not.
- choices: ['present', 'absent']
- default: 'present'
-
- service_state:
- description:
- - Whether the specified aggregate should be enabled or disabled. Creates aggregate if doesnt exist.
- choices: ['online', 'offline']
-
- name:
- required: true
- description:
- - The name of the aggregate to manage.
-
- from_name:
- description:
- - Name of the aggregate to be renamed.
- version_added: '2.7'
-
- nodes:
- description:
- - Node(s) for the aggregate to be created on. If no node specified, mgmt lif home will be used.
- - If multiple nodes specified an aggr stripe will be made.
-
- disk_type:
- description:
- - Type of disk to use to build aggregate
- choices: ['ATA', 'BSAS', 'FCAL', 'FSAS', 'LUN', 'MSATA', 'SAS', 'SSD', 'VMDISK']
- version_added: '2.7'
-
- disk_count:
- description:
- - Number of disks to place into the aggregate, including parity disks.
- - The disks in this newly-created aggregate come from the spare disk pool.
- - The smallest disks in this pool join the aggregate first, unless the C(disk-size) argument is provided.
- - Either C(disk-count) or C(disks) must be supplied. Range [0..2^31-1].
- - Required when C(state=present).
-
- disk_size:
- description:
- - Disk size to use in 4K block size. Disks within 10% of specified size will be used.
- version_added: '2.7'
-
- raid_size:
- description:
- - Sets the maximum number of drives per raid group.
- version_added: '2.7'
-
- raid_type:
- description:
- - Specifies the type of RAID groups to use in the new aggregate.
- choices: ['raid4', 'raid_dp', 'raid_tec']
- version_added: '2.7'
-
- unmount_volumes:
- type: bool
- description:
- - If set to "TRUE", this option specifies that all of the volumes hosted by the given aggregate are to be unmounted
- - before the offline operation is executed.
- - By default, the system will reject any attempt to offline an aggregate that hosts one or more online volumes.
-
- disks:
- type: list
- description:
- - Specific list of disks to use for the new aggregate.
- - To create a "mirrored" aggregate with a specific list of disks, both 'disks' and 'mirror_disks' options must be supplied.
- Additionally, the same number of disks must be supplied in both lists.
- version_added: '2.8'
-
- is_mirrored:
- type: bool
- description:
- - Specifies that the new aggregate be mirrored (have two plexes).
- - If set to true, then the indicated disks will be split across the two plexes. By default, the new aggregate will not be mirrored.
- - This option cannot be used when a specific list of disks is supplied with either the 'disks' or 'mirror_disks' options.
- version_added: '2.8'
-
- mirror_disks:
- type: list
- description:
- - List of mirror disks to use. It must contain the same number of disks specified in 'disks'.
- version_added: '2.8'
-
- spare_pool:
- description:
- - Specifies the spare pool from which to select spare disks to use in creation of a new aggregate.
- choices: ['Pool0', 'Pool1']
- version_added: '2.8'
-
- wait_for_online:
- description:
- - Set this parameter to 'true' for synchronous execution during create (wait until aggregate status is online)
- - Set this parameter to 'false' for asynchronous execution
- - For asynchronous, execution exits as soon as the request is sent, without checking aggregate status
- type: bool
- default: false
- version_added: '2.8'
-
- time_out:
- description:
- - time to wait for aggregate creation in seconds
- - default is set to 100 seconds
- default: 100
- version_added: "2.8"
-'''
-
-EXAMPLES = """
-- name: Create Aggregates and wait 5 minutes until aggregate is online
- na_ontap_aggregate:
- state: present
- service_state: online
- name: ansibleAggr
- disk_count: 1
- wait_for_online: True
- time_out: 300
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-- name: Manage Aggregates
- na_ontap_aggregate:
- state: present
- service_state: offline
- unmount_volumes: true
- name: ansibleAggr
- disk_count: 1
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-- name: Rename Aggregates
- na_ontap_aggregate:
- state: present
- service_state: online
- from_name: ansibleAggr
- name: ansibleAggr2
- disk_count: 1
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-- name: Delete Aggregates
- na_ontap_aggregate:
- state: absent
- service_state: offline
- unmount_volumes: true
- name: ansibleAggr
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-
-"""
-import time
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapAggregate(object):
- ''' object initialize and class methods '''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- name=dict(required=True, type='str'),
- disks=dict(required=False, type='list'),
- disk_count=dict(required=False, type='int', default=None),
- disk_size=dict(required=False, type='int'),
- disk_type=dict(required=False, choices=['ATA', 'BSAS', 'FCAL', 'FSAS', 'LUN', 'MSATA', 'SAS', 'SSD', 'VMDISK']),
- from_name=dict(required=False, type='str'),
- mirror_disks=dict(required=False, type='list'),
- nodes=dict(required=False, type='list'),
- is_mirrored=dict(required=False, type='bool'),
- raid_size=dict(required=False, type='int'),
- raid_type=dict(required=False, choices=['raid4', 'raid_dp', 'raid_tec']),
- service_state=dict(required=False, choices=['online', 'offline']),
- spare_pool=dict(required=False, choices=['Pool0', 'Pool1']),
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- unmount_volumes=dict(required=False, type='bool'),
- wait_for_online=dict(required=False, type='bool', default=False),
- time_out=dict(required=False, type='int', default=100)
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('service_state', 'offline', ['unmount_volumes']),
- ],
- mutually_exclusive=[
- ('is_mirrored', 'disks'),
- ('is_mirrored', 'mirror_disks'),
- ('is_mirrored', 'spare_pool'),
- ('spare_pool', 'disks')
- ],
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- if self.parameters.get('mirror_disks') is not None and self.parameters.get('disks') is None:
- self.module.fail_json(mgs="mirror_disks require disks options to be set")
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def aggr_get_iter(self, name):
- """
- Return aggr-get-iter query results
- :param name: Name of the aggregate
- :return: NaElement if aggregate found, None otherwise
- """
-
- aggr_get_iter = netapp_utils.zapi.NaElement('aggr-get-iter')
- query_details = netapp_utils.zapi.NaElement.create_node_with_children(
- 'aggr-attributes', **{'aggregate-name': name})
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- aggr_get_iter.add_child_elem(query)
- result = None
- try:
- result = self.server.invoke_successfully(aggr_get_iter, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- # Error 13040 denotes an aggregate not being found.
- if to_native(error.code) == "13040":
- pass
- else:
- self.module.fail_json(msg=to_native(error), exception=traceback.format_exc())
- return result
-
- def get_aggr(self, name=None):
- """
- Fetch details if aggregate exists.
- :param name: Name of the aggregate to be fetched
- :return:
- Dictionary of current details if aggregate found
- None if aggregate is not found
- """
- if name is None:
- name = self.parameters['name']
- aggr_get = self.aggr_get_iter(name)
- if (aggr_get and aggr_get.get_child_by_name('num-records') and
- int(aggr_get.get_child_content('num-records')) >= 1):
- current_aggr = dict()
- attr = aggr_get.get_child_by_name('attributes-list').get_child_by_name('aggr-attributes')
- current_aggr['service_state'] = attr.get_child_by_name('aggr-raid-attributes').get_child_content('state')
- return current_aggr
- return None
-
- def aggregate_online(self):
- """
- Set state of an offline aggregate to online
- :return: None
- """
- online_aggr = netapp_utils.zapi.NaElement.create_node_with_children(
- 'aggr-online', **{'aggregate': self.parameters['name'],
- 'force-online': 'true'})
- try:
- self.server.invoke_successfully(online_aggr,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error changing the state of aggregate %s to %s: %s' %
- (self.parameters['name'], self.parameters['service_state'], to_native(error)),
- exception=traceback.format_exc())
-
- def aggregate_offline(self):
- """
- Set state of an online aggregate to offline
- :return: None
- """
- offline_aggr = netapp_utils.zapi.NaElement.create_node_with_children(
- 'aggr-offline', **{'aggregate': self.parameters['name'],
- 'force-offline': 'false',
- 'unmount-volumes': str(self.parameters['unmount_volumes'])})
- try:
- self.server.invoke_successfully(offline_aggr, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error changing the state of aggregate %s to %s: %s' %
- (self.parameters['name'], self.parameters['service_state'], to_native(error)),
- exception=traceback.format_exc())
-
- def create_aggr(self):
- """
- Create aggregate
- :return: None
- """
- if not self.parameters.get('disk_count'):
- self.module.fail_json(msg='Error provisioning aggregate %s: \
- disk_count is required' % self.parameters['name'])
- options = {'aggregate': self.parameters['name'],
- 'disk-count': str(self.parameters['disk_count'])
- }
- if self.parameters.get('disk_type'):
- options['disk-type'] = self.parameters['disk_type']
- if self.parameters.get('raid_size'):
- options['raid-size'] = str(self.parameters['raid_size'])
- if self.parameters.get('raid_type'):
- options['raid-type'] = self.parameters['raid_type']
- if self.parameters.get('disk_size'):
- options['disk-size'] = str(self.parameters['disk_size'])
- if self.parameters.get('is_mirrored'):
- options['is-mirrored'] = str(self.parameters['is_mirrored'])
- if self.parameters.get('spare_pool'):
- options['spare-pool'] = self.parameters['spare_pool']
- if self.parameters.get('raid_type'):
- options['raid-type'] = self.parameters['raid_type']
- aggr_create = netapp_utils.zapi.NaElement.create_node_with_children('aggr-create', **options)
- if self.parameters.get('nodes'):
- nodes_obj = netapp_utils.zapi.NaElement('nodes')
- aggr_create.add_child_elem(nodes_obj)
- for node in self.parameters['nodes']:
- nodes_obj.add_new_child('node-name', node)
- if self.parameters.get('disks'):
- disks_obj = netapp_utils.zapi.NaElement('disk-info')
- for disk in self.parameters.get('disks'):
- disks_obj.add_new_child('name', disk)
- aggr_create.add_child_elem(disks_obj)
- if self.parameters.get('mirror_disks'):
- mirror_disks_obj = netapp_utils.zapi.NaElement('disk-info')
- for disk in self.parameters.get('mirror_disks'):
- mirror_disks_obj.add_new_child('name', disk)
- aggr_create.add_child_elem(mirror_disks_obj)
-
- try:
- self.server.invoke_successfully(aggr_create, enable_tunneling=False)
- if self.parameters.get('wait_for_online'):
- # round off time_out
- retries = (self.parameters['time_out'] + 5) / 10
- current = self.get_aggr()
- status = None if current is None else current['service_state']
- while status != 'online' and retries > 0:
- time.sleep(10)
- retries = retries - 1
- current = self.get_aggr()
- status = None if current is None else current['service_state']
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error provisioning aggregate %s: %s"
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_aggr(self):
- """
- Delete aggregate.
- :return: None
- """
- aggr_destroy = netapp_utils.zapi.NaElement.create_node_with_children(
- 'aggr-destroy', **{'aggregate': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(aggr_destroy,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error removing aggregate %s: %s" % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def rename_aggregate(self):
- """
- Rename aggregate.
- """
- aggr_rename = netapp_utils.zapi.NaElement.create_node_with_children(
- 'aggr-rename', **{'aggregate': self.parameters['from_name'],
- 'new-aggregate-name': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(aggr_rename, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error renaming aggregate %s: %s"
- % (self.parameters['from_name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_aggr(self, modify):
- """
- Modify state of the aggregate
- :param modify: dictionary of parameters to be modified
- :return: None
- """
- if modify['service_state'] == 'offline':
- self.aggregate_offline()
- elif modify['service_state'] == 'online':
- self.aggregate_online()
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
- def apply(self):
- """
- Apply action to the aggregate
- :return: None
- """
- self.asup_log_for_cserver("na_ontap_aggregate")
-
- current = self.get_aggr()
- # rename and create are mutually exclusive
- rename, cd_action = None, None
- if self.parameters.get('from_name'):
- rename = self.na_helper.is_rename_action(self.get_aggr(self.parameters['from_name']), current)
- if rename is None:
- self.module.fail_json(msg="Error renaming: aggregate %s does not exist" % self.parameters['from_name'])
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_aggregate()
- elif cd_action == 'create':
- self.create_aggr()
- elif cd_action == 'delete':
- self.delete_aggr()
- elif modify:
- self.modify_aggr(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Create Aggregate class instance and invoke apply
- :return: None
- """
- obj_aggr = NetAppOntapAggregate()
- obj_aggr.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_autosupport.py b/lib/ansible/modules/storage/netapp/na_ontap_autosupport.py
deleted file mode 100644
index c77096ee97..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_autosupport.py
+++ /dev/null
@@ -1,275 +0,0 @@
-#!/usr/bin/python
-"""
-create Autosupport module to enable, disable or modify
-"""
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = """
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - "Enable/Disable Autosupport"
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_autosupport
-options:
- state:
- description:
- - Specifies whether the AutoSupport daemon is present or absent.
- - When this setting is absent, delivery of all AutoSupport messages is turned off.
- choices: ['present', 'absent']
- default: present
- node_name:
- description:
- - The name of the filer that owns the AutoSupport Configuration.
- required: true
- transport:
- description:
- - The name of the transport protocol used to deliver AutoSupport messages
- choices: ['http', 'https', 'smtp']
- noteto:
- description:
- - Specifies up to five recipients of short AutoSupport e-mail messages.
- post_url:
- description:
- - The URL used to deliver AutoSupport messages via HTTP POST
- mail_hosts:
- description:
- - List of mail server(s) used to deliver AutoSupport messages via SMTP.
- - Both host names and IP addresses may be used as valid input.
- support:
- description:
- - Specifies whether AutoSupport notification to technical support is enabled.
- type: bool
- from_address:
- description:
- - specify the e-mail address from which the node sends AutoSupport messages
- version_added: 2.8
- partner_addresses:
- description:
- - Specifies up to five partner vendor recipients of full AutoSupport e-mail messages.
- version_added: 2.8
- to_addresses:
- description:
- - Specifies up to five recipients of full AutoSupport e-mail messages.
- version_added: 2.8
- proxy_url:
- description:
- - specify an HTTP or HTTPS proxy if the 'transport' parameter is set to HTTP or HTTPS and your organization uses a proxy.
- - If authentication is required, use the format "username:password@host:port".
- version_added: 2.8
- hostname_in_subject:
- description:
- - Specify whether the hostname of the node is included in the subject line of the AutoSupport message.
- type: bool
- version_added: 2.8
-short_description: NetApp ONTAP Autosupport
-version_added: "2.7"
-
-"""
-
-EXAMPLES = """
- - name: Enable autosupport
- na_ontap_autosupport:
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
- state: present
- node_name: test
- transport: https
- noteto: abc@def.com,def@ghi.com
- mail_hosts: 1.2.3.4,5.6.7.8
- support: False
- post_url: url/1.0/post
-
- - name: Modify autosupport proxy_url with password
- na_ontap_autosupport:
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
- state: present
- node_name: test
- transport: https
- proxy_url: username:password@host.com:8000
-
- - name: Modify autosupport proxy_url without password
- na_ontap_autosupport:
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
- state: present
- node_name: test
- transport: https
- proxy_url: username@host.com:8000
-
- - name: Disable autosupport
- na_ontap_autosupport:
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
- state: absent
- node_name: test
-
-"""
-
-RETURN = """
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPasup(object):
- """Class with autosupport methods"""
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- node_name=dict(required=True, type='str'),
- transport=dict(required=False, type='str', choices=['smtp', 'http', 'https']),
- noteto=dict(required=False, type='list'),
- post_url=dict(required=False, type='str'),
- support=dict(required=False, type='bool'),
- mail_hosts=dict(required=False, type='list'),
- from_address=dict(required=False, type='str'),
- partner_addresses=dict(required=False, type='list'),
- to_addresses=dict(required=False, type='list'),
- proxy_url=dict(required=False, type='str'),
- hostname_in_subject=dict(required=False, type='bool'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=False
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- # present or absent requires modifying state to enabled or disabled
- self.parameters['service_state'] = 'started' if self.parameters['state'] == 'present' else 'stopped'
- self.set_playbook_zapi_key_map()
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def set_playbook_zapi_key_map(self):
- self.na_helper.zapi_string_keys = {
- 'node_name': 'node-name',
- 'transport': 'transport',
- 'post_url': 'post-url',
- 'from_address': 'from',
- 'proxy_url': 'proxy-url'
- }
- self.na_helper.zapi_list_keys = {
- 'noteto': ('noteto', 'mail-address'),
- 'mail_hosts': ('mail-hosts', 'string'),
- 'partner_addresses': ('partner-address', 'mail-address'),
- 'to_addresses': ('to', 'mail-address'),
- }
- self.na_helper.zapi_bool_keys = {
- 'support': 'is-support-enabled',
- 'hostname_in_subject': 'is-node-in-subject'
- }
-
- def get_autosupport_config(self):
- """
- Invoke zapi - get current autosupport details
- :return: dict()
- """
- asup_details = netapp_utils.zapi.NaElement('autosupport-config-get')
- asup_details.add_new_child('node-name', self.parameters['node_name'])
- asup_info = dict()
- try:
- result = self.server.invoke_successfully(asup_details, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='%s' % to_native(error),
- exception=traceback.format_exc())
- # zapi invoke successful
- asup_attr_info = result.get_child_by_name('attributes').get_child_by_name('autosupport-config-info')
- asup_info['service_state'] = 'started' if asup_attr_info['is-enabled'] == 'true' else 'stopped'
- for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
- asup_info[item_key] = asup_attr_info[zapi_key]
- for item_key, zapi_key in self.na_helper.zapi_bool_keys.items():
- asup_info[item_key] = self.na_helper.get_value_for_bool(from_zapi=True,
- value=asup_attr_info[zapi_key])
- for item_key, zapi_key in self.na_helper.zapi_list_keys.items():
- parent, dummy = zapi_key
- asup_info[item_key] = self.na_helper.get_value_for_list(from_zapi=True,
- zapi_parent=asup_attr_info.get_child_by_name(parent)
- )
- return asup_info
-
- def modify_autosupport_config(self, modify):
- """
- Invoke zapi - modify autosupport config
- @return: NaElement object / FAILURE with an error_message
- """
- asup_details = {'node-name': self.parameters['node_name']}
- if modify.get('service_state'):
- asup_details['is-enabled'] = 'true' if modify.get('service_state') == 'started' else 'false'
- asup_config = netapp_utils.zapi.NaElement('autosupport-config-modify')
- for item_key in modify:
- if item_key in self.na_helper.zapi_string_keys:
- zapi_key = self.na_helper.zapi_string_keys.get(item_key)
- asup_details[zapi_key] = modify[item_key]
- elif item_key in self.na_helper.zapi_bool_keys:
- zapi_key = self.na_helper.zapi_bool_keys.get(item_key)
- asup_details[zapi_key] = self.na_helper.get_value_for_bool(from_zapi=False,
- value=modify[item_key])
- elif item_key in self.na_helper.zapi_list_keys:
- parent_key, child_key = self.na_helper.zapi_list_keys.get(item_key)
- asup_config.add_child_elem(self.na_helper.get_value_for_list(from_zapi=False,
- zapi_parent=parent_key,
- zapi_child=child_key,
- data=modify.get(item_key)))
- asup_config.translate_struct(asup_details)
- try:
- return self.server.invoke_successfully(asup_config, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='%s' % to_native(error), exception=traceback.format_exc())
-
- def autosupport_log(self):
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_autosupport", cserver)
-
- def apply(self):
- """
- Apply action to autosupport
- """
- current = self.get_autosupport_config()
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- self.modify_autosupport_config(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """Execute action"""
- asup_obj = NetAppONTAPasup()
- asup_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain.py b/lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain.py
deleted file mode 100644
index 561efc5f9a..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain.py
+++ /dev/null
@@ -1,436 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_broadcast_domain
-short_description: NetApp ONTAP manage broadcast domains.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Modify a ONTAP broadcast domain.
-options:
- state:
- description:
- - Whether the specified broadcast domain should exist or not.
- choices: ['present', 'absent']
- default: present
- name:
- description:
- - Specify the broadcast domain name.
- required: true
- aliases:
- - broadcast_domain
- from_name:
- description:
- - Specify the broadcast domain name to be split into new broadcast domain.
- version_added: "2.8"
- mtu:
- description:
- - Specify the required mtu for the broadcast domain.
- ipspace:
- description:
- - Specify the required ipspace for the broadcast domain.
- - A domain ipspace can not be modified after the domain has been created.
- ports:
- description:
- - Specify the ports associated with this broadcast domain. Should be comma separated.
- - It represents the expected state of a list of ports at any time.
- - Add a port if it is specified in expected state but not in current state.
- - Delete a port if it is specified in current state but not in expected state.
- - For split action, it represents the ports to be split from current broadcast domain and added to the new broadcast domain.
- - if all ports are removed or split from a broadcast domain, the broadcast domain will be deleted automatically.
-'''
-
-EXAMPLES = """
- - name: create broadcast domain
- na_ontap_broadcast_domain:
- state: present
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- name: ansible_domain
- mtu: 1000
- ipspace: Default
- ports: ["khutton-vsim1:e0d-12", "khutton-vsim1:e0d-13"]
- - name: modify broadcast domain
- na_ontap_broadcast_domain:
- state: present
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- name: ansible_domain
- mtu: 1100
- ipspace: Default
- ports: ["khutton-vsim1:e0d-12", "khutton-vsim1:e0d-13"]
- - name: split broadcast domain
- na_ontap_broadcast_domain:
- state: present
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- from_name: ansible_domain
- name: new_ansible_domain
- mtu: 1200
- ipspace: Default
- ports: khutton-vsim1:e0d-12
- - name: delete broadcast domain
- na_ontap_broadcast_domain:
- state: absent
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- name: ansible_domain
- ipspace: Default
-"""
-
-RETURN = """
-
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapBroadcastDomain(object):
- """
- Create, Modifies and Destroys a Broadcast domain
- """
- def __init__(self):
- """
- Initialize the ONTAP Broadcast Domain class
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str', aliases=["broadcast_domain"]),
- ipspace=dict(required=False, type='str'),
- mtu=dict(required=False, type='str'),
- ports=dict(required=False, type='list'),
- from_name=dict(required=False, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- return
-
- def get_broadcast_domain(self, broadcast_domain=None):
- """
- Return details about the broadcast domain
- :param broadcast_domain: specific broadcast domain to get.
- :return: Details about the broadcast domain. None if not found.
- :rtype: dict
- """
- if broadcast_domain is None:
- broadcast_domain = self.parameters['name']
- domain_get_iter = netapp_utils.zapi.NaElement('net-port-broadcast-domain-get-iter')
- broadcast_domain_info = netapp_utils.zapi.NaElement('net-port-broadcast-domain-info')
- broadcast_domain_info.add_new_child('broadcast-domain', broadcast_domain)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(broadcast_domain_info)
- domain_get_iter.add_child_elem(query)
- result = self.server.invoke_successfully(domain_get_iter, True)
- domain_exists = None
- # check if broadcast_domain exists
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
- domain_info = result.get_child_by_name('attributes-list').\
- get_child_by_name('net-port-broadcast-domain-info')
- domain_name = domain_info.get_child_content('broadcast-domain')
- domain_mtu = domain_info.get_child_content('mtu')
- domain_ipspace = domain_info.get_child_content('ipspace')
- domain_ports = domain_info.get_child_by_name('ports')
- if domain_ports is not None:
- ports = [port.get_child_content('port') for port in domain_ports.get_children()]
- else:
- ports = []
- domain_exists = {
- 'domain-name': domain_name,
- 'mtu': domain_mtu,
- 'ipspace': domain_ipspace,
- 'ports': ports
- }
- return domain_exists
-
- def create_broadcast_domain(self):
- """
- Creates a new broadcast domain
- """
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-create')
- domain_obj.add_new_child("broadcast-domain", self.parameters['name'])
- if self.parameters.get('ipspace'):
- domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
- if self.parameters.get('mtu'):
- domain_obj.add_new_child("mtu", self.parameters['mtu'])
- if self.parameters.get('ports'):
- ports_obj = netapp_utils.zapi.NaElement('ports')
- domain_obj.add_child_elem(ports_obj)
- for port in self.parameters['ports']:
- ports_obj.add_new_child('net-qualified-port-name', port)
- try:
- self.server.invoke_successfully(domain_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating broadcast domain %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_broadcast_domain(self, broadcast_domain=None):
- """
- Deletes a broadcast domain
- """
- if broadcast_domain is None:
- broadcast_domain = self.parameters['name']
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-destroy')
- domain_obj.add_new_child("broadcast-domain", broadcast_domain)
- if self.parameters.get('ipspace'):
- domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
- try:
- self.server.invoke_successfully(domain_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting broadcast domain %s: %s' %
- (broadcast_domain, to_native(error)),
- exception=traceback.format_exc())
-
- def modify_broadcast_domain(self):
- """
- Modifies ipspace and mtu options of a broadcast domain
- """
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-modify')
- domain_obj.add_new_child("broadcast-domain", self.parameters['name'])
- if self.parameters.get('mtu'):
- domain_obj.add_new_child("mtu", self.parameters['mtu'])
- if self.parameters.get('ipspace'):
- domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
- try:
- self.server.invoke_successfully(domain_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying broadcast domain %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def split_broadcast_domain(self):
- """
- split broadcast domain
- """
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-split')
- domain_obj.add_new_child("broadcast-domain", self.parameters['from_name'])
- domain_obj.add_new_child("new-broadcast-domain", self.parameters['name'])
- if self.parameters.get('ports'):
- ports_obj = netapp_utils.zapi.NaElement('ports')
- domain_obj.add_child_elem(ports_obj)
- for port in self.parameters['ports']:
- ports_obj.add_new_child('net-qualified-port-name', port)
- if self.parameters.get('ipspace'):
- domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
- try:
- self.server.invoke_successfully(domain_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error splitting broadcast domain %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- if len(self.get_broadcast_domain_ports(self.parameters['from_name'])) == 0:
- self.delete_broadcast_domain(self.parameters['from_name'])
-
- def modify_redirect(self, modify):
- """
- :param modify: modify attributes.
- """
- for attribute in modify.keys():
- if attribute == 'mtu':
- self.modify_broadcast_domain()
- if attribute == 'ports':
- self.modify_broadcast_domain_ports()
-
- def get_modify_attributes(self, current, split):
- """
- :param current: current state.
- :param split: True or False of split action.
- :return: list of modified attributes.
- """
- modify = None
- if self.parameters['state'] == 'present':
- # split already handled ipspace and ports.
- if self.parameters.get('from_name'):
- current = self.get_broadcast_domain(self.parameters['from_name'])
- if split:
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if modify.get('ipspace'):
- del modify['ipspace']
- if modify.get('ports'):
- del modify['ports']
- # ipspace can not be modified.
- else:
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if modify.get('ipspace'):
- self.module.fail_json(msg='A domain ipspace can not be modified after the domain has been created.',
- exception=traceback.format_exc())
- return modify
-
- def modify_broadcast_domain_ports(self):
- """
- compare current and desire ports. Call add or remove ports methods if needed.
- :return: None.
- """
- current_ports = self.get_broadcast_domain_ports()
- expect_ports = self.parameters['ports']
- # if want to remove all ports, simply delete the broadcast domain.
- if len(expect_ports) == 0:
- self.delete_broadcast_domain()
- return
- ports_to_remove = list(set(current_ports) - set(expect_ports))
- ports_to_add = list(set(expect_ports) - set(current_ports))
-
- if len(ports_to_add) > 0:
- self.add_broadcast_domain_ports(ports_to_add)
-
- if len(ports_to_remove) > 0:
- self.delete_broadcast_domain_ports(ports_to_remove)
-
- def add_broadcast_domain_ports(self, ports):
- """
- Creates new broadcast domain ports
- """
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-add-ports')
- domain_obj.add_new_child("broadcast-domain", self.parameters['name'])
- if self.parameters.get('ipspace'):
- domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
- if ports:
- ports_obj = netapp_utils.zapi.NaElement('ports')
- domain_obj.add_child_elem(ports_obj)
- for port in ports:
- ports_obj.add_new_child('net-qualified-port-name', port)
- try:
- self.server.invoke_successfully(domain_obj, True)
- return True
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating port for broadcast domain %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_broadcast_domain_ports(self, ports):
- """
- Deletes broadcast domain ports
- :param: ports to be deleted.
- """
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-remove-ports')
- domain_obj.add_new_child("broadcast-domain", self.parameters['name'])
- if self.parameters.get('ipspace'):
- domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
- if ports:
- ports_obj = netapp_utils.zapi.NaElement('ports')
- domain_obj.add_child_elem(ports_obj)
- for port in ports:
- ports_obj.add_new_child('net-qualified-port-name', port)
- try:
- self.server.invoke_successfully(domain_obj, True)
- return True
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting port for broadcast domain %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def get_broadcast_domain_ports(self, broadcast_domain=None):
- """
- Return details about the broadcast domain ports.
- :return: Details about the broadcast domain ports. None if not found.
- :rtype: list
- """
- if broadcast_domain is None:
- broadcast_domain = self.parameters['name']
- domain_get_iter = netapp_utils.zapi.NaElement('net-port-broadcast-domain-get-iter')
- broadcast_domain_info = netapp_utils.zapi.NaElement('net-port-broadcast-domain-info')
- broadcast_domain_info.add_new_child('broadcast-domain', broadcast_domain)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(broadcast_domain_info)
- domain_get_iter.add_child_elem(query)
- result = self.server.invoke_successfully(domain_get_iter, True)
- ports = []
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
- domain_info = result.get_child_by_name('attributes-list').get_child_by_name('net-port-broadcast-domain-info')
- domain_ports = domain_info.get_child_by_name('ports')
- if domain_ports is not None:
- ports = [port.get_child_content('port') for port in domain_ports.get_children()]
- return ports
-
- def apply(self):
- """
- Run Module based on play book
- """
- self.asup_log_for_cserver("na_ontap_broadcast_domain")
- current = self.get_broadcast_domain()
- cd_action, split = None, None
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action == 'create':
- # either create new domain or split domain.
- if self.parameters.get('from_name'):
- split = self.na_helper.is_rename_action(self.get_broadcast_domain(self.parameters['from_name']), current)
- if split is None:
- self.module.fail_json(msg='A domain can not be split if it does not exist.',
- exception=traceback.format_exc())
- if split:
- cd_action = None
- modify = self.get_modify_attributes(current, split)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if split:
- self.split_broadcast_domain()
- if cd_action == 'create':
- self.create_broadcast_domain()
- elif cd_action == 'delete':
- self.delete_broadcast_domain()
- elif modify:
- self.modify_redirect(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
-
-def main():
- """
- Creates the NetApp ONTAP Broadcast Domain Object that can be created, deleted and modified.
- """
- obj = NetAppOntapBroadcastDomain()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain_ports.py b/lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain_ports.py
deleted file mode 100644
index 8b37e49590..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain_ports.py
+++ /dev/null
@@ -1,215 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_broadcast_domain_ports
-short_description: NetApp ONTAP manage broadcast domain ports
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Add or remove ONTAP broadcast domain ports. Existing ports that are not listed are kept.
-options:
- state:
- description:
- - Whether the specified broadcast domain should exist or not.
- choices: ['present', 'absent']
- default: present
- broadcast_domain:
- description:
- - Specify the broadcast_domain name
- required: true
- ipspace:
- description:
- - Specify the ipspace for the broadcast domain
- ports:
- description:
- - Specify the list of ports to add to or remove from this broadcast domain.
-
-'''
-
-EXAMPLES = """
- - name: create broadcast domain ports
- na_ontap_broadcast_domain_ports:
- state=present
- username={{ netapp_username }}
- password={{ netapp_password }}
- hostname={{ netapp_hostname }}
- broadcast_domain=123kevin
- ports=khutton-vsim1:e0d-13
- - name: delete broadcast domain ports
- na_ontap_broadcast_domain_ports:
- state=absent
- username={{ netapp_username }}
- password={{ netapp_password }}
- hostname={{ netapp_hostname }}
- broadcast_domain=123kevin
- ports=khutton-vsim1:e0d-13
-"""
-
-RETURN = """
-
-
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapBroadcastDomainPorts(object):
- """
- Create and Destroys Broadcast Domain Ports
- """
- def __init__(self):
- """
- Initialize the Ontap Net Route class
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- broadcast_domain=dict(required=True, type='str'),
- ipspace=dict(required=False, type='str', default=None),
- ports=dict(required=True, type='list'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- parameters = self.module.params
- # set up state variables
- self.state = parameters['state']
- self.broadcast_domain = parameters['broadcast_domain']
- self.ipspace = parameters['ipspace']
- self.ports = parameters['ports']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- return
-
- def get_broadcast_domain_ports(self):
- """
- Return details about the broadcast domain ports
- :param:
- name : broadcast domain name
- :return: Details about the broadcast domain. None if not found.
- :rtype: dict
- """
- domain_get_iter = netapp_utils.zapi.NaElement('net-port-broadcast-domain-get-iter')
- broadcast_domain_info = netapp_utils.zapi.NaElement('net-port-broadcast-domain-info')
- broadcast_domain_info.add_new_child('broadcast-domain', self.broadcast_domain)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(broadcast_domain_info)
- domain_get_iter.add_child_elem(query)
- result = self.server.invoke_successfully(domain_get_iter, True)
- domain_exists = None
- # check if broadcast domain exists
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
- domain_info = result.get_child_by_name('attributes-list').get_child_by_name('net-port-broadcast-domain-info')
- domain_name = domain_info.get_child_content('broadcast-domain')
- domain_ports = domain_info.get_child_by_name('ports')
- if domain_ports is not None:
- ports = [port.get_child_content('port') for port in domain_ports.get_children()]
- else:
- ports = []
- domain_exists = {
- 'domain-name': domain_name,
- 'ports': ports
- }
- return domain_exists
-
- def create_broadcast_domain_ports(self, ports):
- """
- Creates new broadcast domain ports
- """
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-add-ports')
- domain_obj.add_new_child("broadcast-domain", self.broadcast_domain)
- if self.ipspace:
- domain_obj.add_new_child("ipspace", self.ipspace)
- if ports:
- ports_obj = netapp_utils.zapi.NaElement('ports')
- domain_obj.add_child_elem(ports_obj)
- for port in ports:
- ports_obj.add_new_child('net-qualified-port-name', port)
- try:
- self.server.invoke_successfully(domain_obj, True)
- return True
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating port for broadcast domain %s: %s' %
- (self.broadcast_domain, to_native(error)),
- exception=traceback.format_exc())
-
- def delete_broadcast_domain_ports(self, ports):
- """
- Deletes broadcast domain ports
- """
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-remove-ports')
- domain_obj.add_new_child("broadcast-domain", self.broadcast_domain)
- if self.ipspace:
- domain_obj.add_new_child("ipspace", self.ipspace)
- if ports:
- ports_obj = netapp_utils.zapi.NaElement('ports')
- domain_obj.add_child_elem(ports_obj)
- for port in ports:
- ports_obj.add_new_child('net-qualified-port-name', port)
- try:
- self.server.invoke_successfully(domain_obj, True)
- return True
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting port for broadcast domain %s: %s' %
- (self.broadcast_domain, to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Run Module based on play book
- """
- changed = False
- broadcast_domain_details = self.get_broadcast_domain_ports()
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_broadcast_domain_ports", cserver)
- if broadcast_domain_details is None:
- self.module.fail_json(msg='Error broadcast domain not found: %s' % self.broadcast_domain)
- if self.module.check_mode:
- pass
- else:
- if self.state == 'present': # execute create
- ports_to_add = [port for port in self.ports if port not in broadcast_domain_details['ports']]
- if len(ports_to_add) > 0:
- changed = self.create_broadcast_domain_ports(ports_to_add)
- elif self.state == 'absent': # execute delete
- ports_to_delete = [port for port in self.ports if port in broadcast_domain_details['ports']]
- if len(ports_to_delete) > 0:
- changed = self.delete_broadcast_domain_ports(ports_to_delete)
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Creates the NetApp Ontap Net Route object and runs the correct play task
- """
- obj = NetAppOntapBroadcastDomainPorts()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_cg_snapshot.py b/lib/ansible/modules/storage/netapp/na_ontap_cg_snapshot.py
deleted file mode 100644
index 2500509011..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_cg_snapshot.py
+++ /dev/null
@@ -1,219 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-short_description: NetApp ONTAP manage consistency group snapshot
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Create consistency group snapshot for ONTAP volumes.
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_cg_snapshot
-options:
- state:
- description:
- - If you want to create a snapshot.
- default: present
- vserver:
- required: true
- description:
- - Name of the vserver.
- volumes:
- required: true
- description:
- - A list of volumes in this filer that is part of this CG operation.
- snapshot:
- required: true
- description:
- - The provided name of the snapshot that is created in each volume.
- timeout:
- description:
- - Timeout selector.
- choices: ['urgent', 'medium', 'relaxed']
- default: medium
- snapmirror_label:
- description:
- - A human readable SnapMirror label to be attached with the consistency group snapshot copies.
-version_added: "2.7"
-
-'''
-
-EXAMPLES = """
- - name:
- na_ontap_cg_snapshot:
- state: present
- vserver: vserver_name
- snapshot: snapshot name
- volumes: vol_name
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
- hostname: "{{ netapp hostname }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPCGSnapshot(object):
- """
- Methods to create CG snapshots
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, default='present'),
- vserver=dict(required=True, type='str'),
- volumes=dict(required=True, type='list'),
- snapshot=dict(required=True, type='str'),
- timeout=dict(required=False, type='str', choices=[
- 'urgent', 'medium', 'relaxed'], default='medium'),
- snapmirror_label=dict(required=False, type='str')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- parameters = self.module.params
-
- # set up variables
- self.state = parameters['state']
- self.vserver = parameters['vserver']
- self.volumes = parameters['volumes']
- self.snapshot = parameters['snapshot']
- self.timeout = parameters['timeout']
- self.snapmirror_label = parameters['snapmirror_label']
- self.cgid = None
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=self.vserver)
-
- def does_snapshot_exist(self, volume):
- """
- This is duplicated from na_ontap_snapshot
- Checks to see if a snapshot exists or not
- :return: Return True if a snapshot exists, false if it doesn't
- """
- # TODO: Remove this method and import snapshot module and
- # call get after re-factoring __init__ across all the modules
- # we aren't importing now, since __init__ does a lot of Ansible setup
- snapshot_obj = netapp_utils.zapi.NaElement("snapshot-get-iter")
- desired_attr = netapp_utils.zapi.NaElement("desired-attributes")
- snapshot_info = netapp_utils.zapi.NaElement('snapshot-info')
- comment = netapp_utils.zapi.NaElement('comment')
- # add more desired attributes that are allowed to be modified
- snapshot_info.add_child_elem(comment)
- desired_attr.add_child_elem(snapshot_info)
- snapshot_obj.add_child_elem(desired_attr)
- # compose query
- query = netapp_utils.zapi.NaElement("query")
- snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-info")
- snapshot_info_obj.add_new_child("name", self.snapshot)
- snapshot_info_obj.add_new_child("volume", volume)
- snapshot_info_obj.add_new_child("vserver", self.vserver)
- query.add_child_elem(snapshot_info_obj)
- snapshot_obj.add_child_elem(query)
- result = self.server.invoke_successfully(snapshot_obj, True)
- return_value = None
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
- attributes_list = result.get_child_by_name('attributes-list')
- snap_info = attributes_list.get_child_by_name('snapshot-info')
- return_value = {'comment': snap_info.get_child_content('comment')}
- return return_value
-
- def cgcreate(self):
- """
- Calls cg-start and cg-commit (when cg-start succeeds)
- """
- started = self.cg_start()
- if started:
- if self.cgid is not None:
- self.cg_commit()
- else:
- self.module.fail_json(msg="Error fetching CG ID for CG commit %s" % self.snapshot,
- exception=traceback.format_exc())
- return started
-
- def cg_start(self):
- """
- For the given list of volumes, creates cg-snapshot
- """
- snapshot_started = False
- cgstart = netapp_utils.zapi.NaElement("cg-start")
- cgstart.add_new_child("snapshot", self.snapshot)
- cgstart.add_new_child("timeout", self.timeout)
- volume_list = netapp_utils.zapi.NaElement("volumes")
- cgstart.add_child_elem(volume_list)
- for vol in self.volumes:
- snapshot_exists = self.does_snapshot_exist(vol)
- if snapshot_exists is None:
- snapshot_started = True
- volume_list.add_new_child("volume-name", vol)
- if snapshot_started:
- if self.snapmirror_label:
- cgstart.add_new_child("snapmirror-label",
- self.snapmirror_label)
- try:
- cgresult = self.server.invoke_successfully(
- cgstart, enable_tunneling=True)
- if cgresult.get_child_by_name('cg-id'):
- self.cgid = cgresult['cg-id']
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error creating CG snapshot %s: %s" %
- (self.snapshot, to_native(error)),
- exception=traceback.format_exc())
- return snapshot_started
-
- def cg_commit(self):
- """
- When cg-start is successful, performs a cg-commit with the cg-id
- """
- cgcommit = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cg-commit', **{'cg-id': self.cgid})
- try:
- self.server.invoke_successfully(cgcommit,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error committing CG snapshot %s: %s" %
- (self.snapshot, to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- '''Applies action from playbook'''
- netapp_utils.ems_log_event("na_ontap_cg_snapshot", self.server)
- changed = self.cgcreate()
- self.module.exit_json(changed=changed)
-
-
-def main():
- '''Execute action from playbook'''
- cg_obj = NetAppONTAPCGSnapshot()
- cg_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_cifs.py b/lib/ansible/modules/storage/netapp/na_ontap_cifs.py
deleted file mode 100644
index 160e7ee1da..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_cifs.py
+++ /dev/null
@@ -1,306 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-# import untangle
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - "Create or destroy or modify(path) cifs-share on ONTAP"
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_cifs
-
-options:
-
- path:
- description:
- The file system path that is shared through this CIFS share. The path is the full, user visible path relative
- to the vserver root, and it might be crossing junction mount points. The path is in UTF8 and uses forward
- slash as directory separator
- required: false
-
- vserver:
- description:
- - "Vserver containing the CIFS share."
- required: true
-
- share_name:
- description:
- The name of the CIFS share. The CIFS share name is a UTF-8 string with the following characters being
- illegal; control characters from 0x00 to 0x1F, both inclusive, 0x22 (double quotes)
- required: true
-
- share_properties:
- description:
- - The list of properties for the CIFS share
- required: false
- version_added: '2.8'
-
- symlink_properties:
- description:
- - The list of symlink properties for this CIFS share
- required: false
- version_added: '2.8'
-
- state:
- choices: ['present', 'absent']
- description:
- - "Whether the specified CIFS share should exist or not."
- required: false
- default: present
-
- vscan_fileop_profile:
- choices: ['no_scan', 'standard', 'strict', 'writes_only']
- description:
- - Profile_set of file_ops to which vscan on access scanning is applicable.
- required: false
- version_added: '2.9'
-
-short_description: NetApp ONTAP Manage cifs-share
-version_added: "2.6"
-
-'''
-
-EXAMPLES = """
- - name: Create CIFS share
- na_ontap_cifs:
- state: present
- share_name: cifsShareName
- path: /
- vserver: vserverName
- share_properties: browsable,oplocks
- symlink_properties: read_only,enable
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Delete CIFS share
- na_ontap_cifs:
- state: absent
- share_name: cifsShareName
- vserver: vserverName
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Modify path CIFS share
- na_ontap_cifs:
- state: present
- share_name: pb_test
- vserver: vserverName
- path: /
- share_properties: show_previous_versions
- symlink_properties: disable
- vscan_fileop_profile: no_scan
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPCifsShare(object):
- """
- Methods to create/delete/modify(path) CIFS share
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=[
- 'present', 'absent'], default='present'),
- share_name=dict(required=True, type='str'),
- path=dict(required=False, type='str'),
- vserver=dict(required=True, type='str'),
- share_properties=dict(required=False, type='list'),
- symlink_properties=dict(required=False, type='list'),
- vscan_fileop_profile=dict(required=False, type='str', choices=['no_scan', 'standard', 'strict', 'writes_only'])
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=self.parameters.get('vserver'))
-
- def get_cifs_share(self):
- """
- Return details about the cifs-share
- :param:
- name : Name of the cifs-share
- :return: Details about the cifs-share. None if not found.
- :rtype: dict
- """
- cifs_iter = netapp_utils.zapi.NaElement('cifs-share-get-iter')
- cifs_info = netapp_utils.zapi.NaElement('cifs-share')
- cifs_info.add_new_child('share-name', self.parameters.get('share_name'))
- cifs_info.add_new_child('vserver', self.parameters.get('vserver'))
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(cifs_info)
-
- cifs_iter.add_child_elem(query)
-
- result = self.server.invoke_successfully(cifs_iter, True)
-
- return_value = None
- # check if query returns the expected cifs-share
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
- properties_list = []
- symlink_list = []
- cifs_attrs = result.get_child_by_name('attributes-list').\
- get_child_by_name('cifs-share')
- if cifs_attrs.get_child_by_name('share-properties'):
- properties_attrs = cifs_attrs['share-properties']
- if properties_attrs is not None:
- properties_list = [property.get_content() for property in properties_attrs.get_children()]
- if cifs_attrs.get_child_by_name('symlink-properties'):
- symlink_attrs = cifs_attrs['symlink-properties']
- if symlink_attrs is not None:
- symlink_list = [symlink.get_content() for symlink in symlink_attrs.get_children()]
- return_value = {
- 'share': cifs_attrs.get_child_content('share-name'),
- 'path': cifs_attrs.get_child_content('path'),
- 'share_properties': properties_list,
- 'symlink_properties': symlink_list
- }
- if cifs_attrs.get_child_by_name('vscan-fileop-profile'):
- return_value['vscan_fileop_profile'] = cifs_attrs['vscan-fileop-profile']
-
- return return_value
-
- def create_cifs_share(self):
- """
- Create CIFS share
- """
- options = {'share-name': self.parameters.get('share_name'),
- 'path': self.parameters.get('path')}
- cifs_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-share-create', **options)
- if self.parameters.get('share_properties'):
- property_attrs = netapp_utils.zapi.NaElement('share-properties')
- cifs_create.add_child_elem(property_attrs)
- for property in self.parameters.get('share_properties'):
- property_attrs.add_new_child('cifs-share-properties', property)
- if self.parameters.get('symlink_properties'):
- symlink_attrs = netapp_utils.zapi.NaElement('symlink-properties')
- cifs_create.add_child_elem(symlink_attrs)
- for symlink in self.parameters.get('symlink_properties'):
- symlink_attrs.add_new_child('cifs-share-symlink-properties', symlink)
- if self.parameters.get('vscan_fileop_profile'):
- fileop_attrs = netapp_utils.zapi.NaElement('vscan-fileop-profile')
- fileop_attrs.set_content(self.parameters['vscan_fileop_profile'])
- cifs_create.add_child_elem(fileop_attrs)
-
- try:
- self.server.invoke_successfully(cifs_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
-
- self.module.fail_json(msg='Error creating cifs-share %s: %s'
- % (self.parameters.get('share_name'), to_native(error)),
- exception=traceback.format_exc())
-
- def delete_cifs_share(self):
- """
- Delete CIFS share
- """
- cifs_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-share-delete', **{'share-name': self.parameters.get('share_name')})
-
- try:
- self.server.invoke_successfully(cifs_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting cifs-share %s: %s'
- % (self.parameters.get('share_name'), to_native(error)),
- exception=traceback.format_exc())
-
- def modify_cifs_share(self):
- """
- modify path for the given CIFS share
- """
- options = {'share-name': self.parameters.get('share_name')}
- cifs_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-share-modify', **options)
- if self.parameters.get('path'):
- cifs_modify.add_new_child('path', self.parameters.get('path'))
- if self.parameters.get('share_properties'):
- property_attrs = netapp_utils.zapi.NaElement('share-properties')
- cifs_modify.add_child_elem(property_attrs)
- for property in self.parameters.get('share_properties'):
- property_attrs.add_new_child('cifs-share-properties', property)
- if self.parameters.get('symlink_properties'):
- symlink_attrs = netapp_utils.zapi.NaElement('symlink-properties')
- cifs_modify.add_child_elem(symlink_attrs)
- for property in self.parameters.get('symlink_properties'):
- symlink_attrs.add_new_child('cifs-share-symlink-properties', property)
- if self.parameters.get('vscan_fileop_profile'):
- fileop_attrs = netapp_utils.zapi.NaElement('vscan-fileop-profile')
- fileop_attrs.set_content(self.parameters['vscan_fileop_profile'])
- cifs_modify.add_child_elem(fileop_attrs)
- try:
- self.server.invoke_successfully(cifs_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying cifs-share %s:%s'
- % (self.parameters.get('share_name'), to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- '''Apply action to cifs share'''
- netapp_utils.ems_log_event("na_ontap_cifs", self.server)
- current = self.get_cifs_share()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action is None:
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_cifs_share()
- elif cd_action == 'delete':
- self.delete_cifs_share()
- elif modify:
- self.modify_cifs_share()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- '''Execute action from playbook'''
- cifs_obj = NetAppONTAPCifsShare()
- cifs_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_cifs_acl.py b/lib/ansible/modules/storage/netapp/na_ontap_cifs_acl.py
deleted file mode 100644
index f159c33752..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_cifs_acl.py
+++ /dev/null
@@ -1,238 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - "Create or destroy or modify cifs-share-access-controls on ONTAP"
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_cifs_acl
-options:
- permission:
- choices: ['no_access', 'read', 'change', 'full_control']
- description:
- -"The access rights that the user or group has on the defined CIFS share."
- share_name:
- description:
- - "The name of the cifs-share-access-control to manage."
- required: true
- state:
- choices: ['present', 'absent']
- description:
- - "Whether the specified CIFS share acl should exist or not."
- default: present
- vserver:
- description:
- - Name of the vserver to use.
- required: true
- user_or_group:
- description:
- - "The user or group name for which the permissions are listed."
- required: true
-short_description: NetApp ONTAP manage cifs-share-access-control
-version_added: "2.6"
-
-'''
-
-EXAMPLES = """
- - name: Create CIFS share acl
- na_ontap_cifs_acl:
- state: present
- share_name: cifsShareName
- user_or_group: Everyone
- permission: read
- vserver: "{{ netapp_vserver }}"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Modify CIFS share acl permission
- na_ontap_cifs_acl:
- state: present
- share_name: cifsShareName
- user_or_group: Everyone
- permission: change
- vserver: "{{ netapp_vserver }}"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPCifsAcl(object):
- """
- Methods to create/delete/modify CIFS share/user access-control
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- share_name=dict(required=True, type='str'),
- user_or_group=dict(required=True, type='str'),
- permission=dict(required=False, type='str', choices=['no_access', 'read', 'change', 'full_control'])
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('state', 'present', ['share_name', 'user_or_group', 'permission'])
- ],
- supports_check_mode=True
- )
- parameters = self.module.params
- # set up state variables
- self.state = parameters['state']
- self.vserver = parameters['vserver']
- self.share_name = parameters['share_name']
- self.user_or_group = parameters['user_or_group']
- self.permission = parameters['permission']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver)
-
- def get_cifs_acl(self):
- """
- Return details about the cifs-share-access-control
- :param:
- name : Name of the cifs-share-access-control
- :return: Details about the cifs-share-access-control. None if not found.
- :rtype: dict
- """
- cifs_acl_iter = netapp_utils.zapi.NaElement('cifs-share-access-control-get-iter')
- cifs_acl_info = netapp_utils.zapi.NaElement('cifs-share-access-control')
- cifs_acl_info.add_new_child('share', self.share_name)
- cifs_acl_info.add_new_child('user-or-group', self.user_or_group)
- cifs_acl_info.add_new_child('vserver', self.vserver)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(cifs_acl_info)
- cifs_acl_iter.add_child_elem(query)
- result = self.server.invoke_successfully(cifs_acl_iter, True)
- return_value = None
- # check if query returns the expected cifs-share-access-control
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
-
- cifs_acl = result.get_child_by_name('attributes-list').get_child_by_name('cifs-share-access-control')
- return_value = {
- 'share': cifs_acl.get_child_content('share'),
- 'user-or-group': cifs_acl.get_child_content('user-or-group'),
- 'permission': cifs_acl.get_child_content('permission')
- }
-
- return return_value
-
- def create_cifs_acl(self):
- """
- Create access control for the given CIFS share/user-group
- """
- cifs_acl_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-share-access-control-create', **{'share': self.share_name,
- 'user-or-group': self.user_or_group,
- 'permission': self.permission})
- try:
- self.server.invoke_successfully(cifs_acl_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
-
- self.module.fail_json(msg='Error creating cifs-share-access-control %s: %s'
- % (self.share_name, to_native(error)),
- exception=traceback.format_exc())
-
- def delete_cifs_acl(self):
- """
- Delete access control for the given CIFS share/user-group
- """
- cifs_acl_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-share-access-control-delete', **{'share': self.share_name,
- 'user-or-group': self.user_or_group})
- try:
- self.server.invoke_successfully(cifs_acl_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting cifs-share-access-control %s: %s'
- % (self.share_name, to_native(error)),
- exception=traceback.format_exc())
-
- def modify_cifs_acl_permission(self):
- """
- Change permission for the given CIFS share/user-group
- """
- cifs_acl_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-share-access-control-modify', **{'share': self.share_name,
- 'user-or-group': self.user_or_group,
- 'permission': self.permission})
- try:
- self.server.invoke_successfully(cifs_acl_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying cifs-share-access-control permission %s:%s'
- % (self.share_name, to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Apply action to cifs-share-access-control
- """
- changed = False
- cifs_acl_exists = False
- netapp_utils.ems_log_event("na_ontap_cifs_acl", self.server)
- cifs_acl_details = self.get_cifs_acl()
- if cifs_acl_details:
- cifs_acl_exists = True
- if self.state == 'absent': # delete
- changed = True
- elif self.state == 'present':
- if cifs_acl_details['permission'] != self.permission: # rename
- changed = True
- else:
- if self.state == 'present': # create
- changed = True
- if changed:
- if self.module.check_mode:
- pass
- else:
- if self.state == 'present': # execute create
- if not cifs_acl_exists:
- self.create_cifs_acl()
- else: # execute modify
- self.modify_cifs_acl_permission()
- elif self.state == 'absent': # execute delete
- self.delete_cifs_acl()
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Execute action from playbook
- """
- cifs_acl = NetAppONTAPCifsAcl()
- cifs_acl.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_cifs_server.py b/lib/ansible/modules/storage/netapp/na_ontap_cifs_server.py
deleted file mode 100644
index b4fc9774e7..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_cifs_server.py
+++ /dev/null
@@ -1,329 +0,0 @@
-#!/usr/bin/python
-""" this is cifs_server module
-
- (c) 2018-2019, NetApp, Inc
- # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'
-}
-
-DOCUMENTATION = '''
----
-module: na_ontap_cifs_server
-short_description: NetApp ONTAP CIFS server configuration
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - Creating / deleting and modifying the CIFS server .
-
-options:
-
- state:
- description:
- - Whether the specified cifs_server should exist or not.
- default: present
- choices: ['present', 'absent']
-
- service_state:
- description:
- - CIFS Server Administrative Status.
- choices: ['stopped', 'started']
-
- name:
- description:
- - Specifies the cifs_server name.
- required: true
- aliases: ['cifs_server_name']
-
- admin_user_name:
- description:
- - Specifies the cifs server admin username.
-
- admin_password:
- description:
- - Specifies the cifs server admin password.
-
- domain:
- description:
- - The Fully Qualified Domain Name of the Windows Active Directory this CIFS server belongs to.
-
- workgroup:
- description:
- - The NetBIOS name of the domain or workgroup this CIFS server belongs to.
-
- ou:
- description:
- - The Organizational Unit (OU) within the Windows Active Directory
- this CIFS server belongs to.
- version_added: '2.7'
-
- force:
- type: bool
- description:
- - If this is set and a machine account with the same name as
- specified in 'name' exists in the Active Directory, it
- will be overwritten and reused.
- version_added: '2.7'
-
- vserver:
- description:
- - The name of the vserver to use.
- required: true
-
-'''
-
-EXAMPLES = '''
- - name: Create cifs_server
- na_ontap_cifs_server:
- state: present
- vserver: svm1
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete cifs_server
- na_ontap_cifs_server:
- state: absent
- name: data2
- vserver: svm1
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-'''
-
-RETURN = '''
-'''
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapcifsServer(object):
- """
- object to describe cifs_server info
- """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- service_state=dict(required=False, choices=['stopped', 'started']),
- name=dict(required=True, type='str', aliases=['cifs_server_name']),
- workgroup=dict(required=False, type='str', default=None),
- domain=dict(required=False, type='str'),
- admin_user_name=dict(required=False, type='str'),
- admin_password=dict(required=False, type='str', no_log=True),
- ou=dict(required=False, type='str'),
- force=dict(required=False, type='bool'),
- vserver=dict(required=True, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- params = self.module.params
-
- # set up state variables
- self.state = params['state']
- self.cifs_server_name = params['cifs_server_name']
- self.workgroup = params['workgroup']
- self.domain = params['domain']
- self.vserver = params['vserver']
- self.service_state = params['service_state']
- self.admin_user_name = params['admin_user_name']
- self.admin_password = params['admin_password']
- self.ou = params['ou']
- self.force = params['force']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver)
-
- def get_cifs_server(self):
- """
- Return details about the CIFS-server
- :param:
- name : Name of the name of the cifs_server
-
- :return: Details about the cifs_server. None if not found.
- :rtype: dict
- """
- cifs_server_info = netapp_utils.zapi.NaElement('cifs-server-get-iter')
- cifs_server_attributes = netapp_utils.zapi.NaElement('cifs-server-config')
- cifs_server_attributes.add_new_child('cifs-server', self.cifs_server_name)
- cifs_server_attributes.add_new_child('vserver', self.vserver)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(cifs_server_attributes)
- cifs_server_info.add_child_elem(query)
- result = self.server.invoke_successfully(cifs_server_info, True)
- return_value = None
-
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) >= 1:
-
- cifs_server_attributes = result.get_child_by_name('attributes-list').\
- get_child_by_name('cifs-server-config')
- return_value = {
- 'cifs_server_name': self.cifs_server_name,
- 'administrative-status': cifs_server_attributes.get_child_content('administrative-status')
- }
-
- return return_value
-
- def create_cifs_server(self):
- """
- calling zapi to create cifs_server
- """
- options = {'cifs-server': self.cifs_server_name, 'administrative-status': 'up'
- if self.service_state == 'started' else 'down'}
- if self.workgroup is not None:
- options['workgroup'] = self.workgroup
- if self.domain is not None:
- options['domain'] = self.domain
- if self.admin_user_name is not None:
- options['admin-username'] = self.admin_user_name
- if self.admin_password is not None:
- options['admin-password'] = self.admin_password
- if self.ou is not None:
- options['organizational-unit'] = self.ou
- if self.force is not None:
- options['force-account-overwrite'] = str(self.force).lower()
-
- cifs_server_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-server-create', **options)
-
- try:
- self.server.invoke_successfully(cifs_server_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as exc:
- self.module.fail_json(msg='Error Creating cifs_server %s: %s' %
- (self.cifs_server_name, to_native(exc)), exception=traceback.format_exc())
-
- def delete_cifs_server(self):
- """
- calling zapi to create cifs_server
- """
- if self.cifs_server_name == 'up':
- self.modify_cifs_server(admin_status='down')
-
- cifs_server_delete = netapp_utils.zapi.NaElement.create_node_with_children('cifs-server-delete')
-
- try:
- self.server.invoke_successfully(cifs_server_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as exc:
- self.module.fail_json(msg='Error deleting cifs_server %s: %s' % (self.cifs_server_name, to_native(exc)),
- exception=traceback.format_exc())
-
- def modify_cifs_server(self, admin_status):
- """
- RModify the cifs_server.
- """
- cifs_server_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-server-modify', **{'cifs-server': self.cifs_server_name,
- 'administrative-status': admin_status, 'vserver': self.vserver})
- try:
- self.server.invoke_successfully(cifs_server_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error modifying cifs_server %s: %s' % (self.cifs_server_name, to_native(e)),
- exception=traceback.format_exc())
-
- def start_cifs_server(self):
- """
- RModify the cifs_server.
- """
- cifs_server_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-server-start')
- try:
- self.server.invoke_successfully(cifs_server_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error modifying cifs_server %s: %s' % (self.cifs_server_name, to_native(e)),
- exception=traceback.format_exc())
-
- def stop_cifs_server(self):
- """
- RModify the cifs_server.
- """
- cifs_server_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cifs-server-stop')
- try:
- self.server.invoke_successfully(cifs_server_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error modifying cifs_server %s: %s' % (self.cifs_server_name, to_native(e)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- calling all cifs_server features
- """
-
- changed = False
- cifs_server_exists = False
- netapp_utils.ems_log_event("na_ontap_cifs_server", self.server)
- cifs_server_detail = self.get_cifs_server()
-
- if cifs_server_detail:
- cifs_server_exists = True
-
- if self.state == 'present':
- administrative_status = cifs_server_detail['administrative-status']
- if self.service_state == 'started' and administrative_status == 'down':
- changed = True
- if self.service_state == 'stopped' and administrative_status == 'up':
- changed = True
- else:
- # we will delete the CIFs server
- changed = True
- else:
- if self.state == 'present':
- changed = True
-
- if changed:
- if self.module.check_mode:
- pass
- else:
- if self.state == 'present':
- if not cifs_server_exists:
- self.create_cifs_server()
-
- elif self.service_state == 'stopped':
- self.stop_cifs_server()
-
- elif self.service_state == 'started':
- self.start_cifs_server()
-
- elif self.state == 'absent':
- self.delete_cifs_server()
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- cifs_server = NetAppOntapcifsServer()
- cifs_server.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_cluster.py b/lib/ansible/modules/storage/netapp/na_ontap_cluster.py
deleted file mode 100644
index 2b3b21d3aa..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_cluster.py
+++ /dev/null
@@ -1,287 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2017-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-module: na_ontap_cluster
-short_description: NetApp ONTAP cluster - create, join, add license
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create or join or apply licenses to ONTAP clusters
-- Cluster join can be performed using only one of the parameters, either cluster_name or cluster_ip_address
-options:
- state:
- description:
- - Whether the specified cluster should exist or not.
- choices: ['present']
- default: present
- cluster_name:
- description:
- - The name of the cluster to manage.
- cluster_ip_address:
- description:
- - IP address of cluster to be joined
- license_code:
- description:
- - License code to be applied to the cluster
- license_package:
- description:
- - License package name of the license to be removed
- node_serial_number:
- description:
- - Serial number of the cluster node
-
-'''
-
-EXAMPLES = """
- - name: Create cluster
- na_ontap_cluster:
- state: present
- cluster_name: new_cluster
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Add license from cluster
- na_ontap_cluster:
- state: present
- cluster_name: FPaaS-A300-01
- license_code: SGHLQDBBVAAAAAAAAAAAAAAAAAAA
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Join cluster
- na_ontap_cluster:
- state: present
- cluster_ip_address: 10.61.184.181
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Join cluster
- na_ontap_cluster:
- state: present
- cluster_name: FPaaS-A300-01
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-def local_cmp(a, b):
- """
- compares with only values and not keys, keys should be the same for both dicts
- :param a: dict 1
- :param b: dict 2
- :return: difference of values in both dicts
- """
- diff = [key for key in a if a[key] != b[key]]
- return len(diff)
-
-
-class NetAppONTAPCluster(object):
- """
- object initialize and class methods
- """
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present'], default='present'),
- cluster_name=dict(required=False, type='str'),
- cluster_ip_address=dict(required=False, type='str'),
- license_code=dict(required=False, type='str'),
- license_package=dict(required=False, type='str'),
- node_serial_number=dict(required=False, type='str')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True,
- required_together=[
- ['license_package', 'node_serial_number']
- ]
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def get_licensing_status(self):
- """
- Check licensing status
-
- :return: package (key) and licensing status (value)
- :rtype: dict
- """
- license_status = netapp_utils.zapi.NaElement(
- 'license-v2-status-list-info')
- try:
- result = self.server.invoke_successfully(license_status,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error checking license status: %s" %
- to_native(error), exception=traceback.format_exc())
-
- return_dictionary = {}
- license_v2_status = result.get_child_by_name('license-v2-status')
- if license_v2_status:
- for license_v2_status_info in license_v2_status.get_children():
- package = license_v2_status_info.get_child_content('package')
- status = license_v2_status_info.get_child_content('method')
- return_dictionary[package] = status
-
- return return_dictionary
-
- def create_cluster(self):
- """
- Create a cluster
- """
- cluster_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cluster-create', **{'cluster-name': self.parameters['cluster_name']})
-
- try:
- self.server.invoke_successfully(cluster_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- # Error 36503 denotes node already being used.
- if to_native(error.code) == "36503":
- return False
- else:
- self.module.fail_json(msg='Error creating cluster %s: %s'
- % (self.parameters['cluster_name'], to_native(error)),
- exception=traceback.format_exc())
- return True
-
- def cluster_join(self):
- """
- Add a node to an existing cluster
- """
- if self.parameters.get('cluster_ip_address') is not None:
- cluster_add_node = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cluster-join', **{'cluster-ip-address': self.parameters['cluster_ip_address']})
- for_fail_attribute = self.parameters.get('cluster_ip_address')
- elif self.parameters.get('cluster_name') is not None:
- cluster_add_node = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cluster-join', **{'cluster-name': self.parameters['cluster_name']})
- for_fail_attribute = self.parameters.get('cluster_name')
- else:
- return False
- try:
- self.server.invoke_successfully(cluster_add_node, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- # Error 36503 denotes node already being used.
- if to_native(error.code) == "36503":
- return False
- else:
- self.module.fail_json(msg='Error adding node to cluster %s: %s'
- % (for_fail_attribute, to_native(error)),
- exception=traceback.format_exc())
- return True
-
- def license_v2_add(self):
- """
- Apply a license to cluster
- """
- license_add = netapp_utils.zapi.NaElement.create_node_with_children('license-v2-add')
- license_add.add_node_with_children('codes', **{'license-code-v2': self.parameters['license_code']})
- try:
- self.server.invoke_successfully(license_add, enable_tunneling=True)
-
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error adding license %s: %s'
- % (self.parameters['license_code'], to_native(error)),
- exception=traceback.format_exc())
-
- def license_v2_delete(self):
- """
- Delete license from cluster
- """
- license_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'license-v2-delete', **{'package': self.parameters['license_package'],
- 'serial-number': self.parameters['node_serial_number']})
- try:
- self.server.invoke_successfully(license_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting license : %s' % (to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- """
- Autosupport log for cluster
- :return:
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_cluster", cserver)
-
- def apply(self):
- """
- Apply action to cluster
- """
- property_changed = False
- create_flag = False
- join_flag = False
-
- self.autosupport_log()
- license_status = self.get_licensing_status()
-
- if self.module.check_mode:
- pass
- else:
- if self.parameters.get('state') == 'present':
- if self.parameters.get('cluster_name') is not None:
- create_flag = self.create_cluster()
- if not create_flag:
- join_flag = self.cluster_join()
- if self.parameters.get('license_code') is not None:
- self.license_v2_add()
- property_changed = True
- if self.parameters.get('license_package') is not None and\
- self.parameters.get('node_serial_number') is not None:
- if license_status.get(str(self.parameters.get('license_package')).lower()) != 'none':
- self.license_v2_delete()
- property_changed = True
- if property_changed:
- new_license_status = self.get_licensing_status()
- if local_cmp(license_status, new_license_status) == 0:
- property_changed = False
- changed = property_changed or create_flag or join_flag
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Create object and call apply
- """
- cluster_obj = NetAppONTAPCluster()
- cluster_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_cluster_ha.py b/lib/ansible/modules/storage/netapp/na_ontap_cluster_ha.py
deleted file mode 100644
index 2d29b0f860..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_cluster_ha.py
+++ /dev/null
@@ -1,133 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - "Enable or disable HA on a cluster"
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_cluster_ha
-options:
- state:
- choices: ['present', 'absent']
- description:
- - "Whether HA on cluster should be enabled or disabled."
- default: present
-short_description: NetApp ONTAP Manage HA status for cluster
-version_added: "2.6"
-'''
-
-EXAMPLES = """
- - name: "Enable HA status for cluster"
- na_ontap_cluster_ha:
- state: present
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapClusterHA(object):
- """
- object initialize and class methods
- """
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def modify_cluster_ha(self, configure):
- """
- Enable or disable HA on cluster
- :return: None
- """
- cluster_ha_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cluster-ha-modify', **{'ha-configured': configure})
- try:
- self.server.invoke_successfully(cluster_ha_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying cluster HA to %s: %s'
- % (configure, to_native(error)),
- exception=traceback.format_exc())
-
- def get_cluster_ha_enabled(self):
- """
- Get current cluster HA details
- :return: dict if enabled, None if disabled
- """
- cluster_ha_get = netapp_utils.zapi.NaElement('cluster-ha-get')
- try:
- result = self.server.invoke_successfully(cluster_ha_get,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching cluster HA details',
- exception=traceback.format_exc())
- cluster_ha_info = result.get_child_by_name('attributes').get_child_by_name('cluster-ha-info')
- if cluster_ha_info.get_child_content('ha-configured') == 'true':
- return {'ha-configured': True}
- return None
-
- def apply(self):
- """
- Apply action to cluster HA
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_cluster_ha", cserver)
- current = self.get_cluster_ha_enabled()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action == 'create':
- self.modify_cluster_ha("true")
- elif cd_action == 'delete':
- self.modify_cluster_ha("false")
-
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Create object and call apply
- """
- ha_obj = NetAppOntapClusterHA()
- ha_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_cluster_peer.py b/lib/ansible/modules/storage/netapp/na_ontap_cluster_peer.py
deleted file mode 100644
index 4bf1598208..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_cluster_peer.py
+++ /dev/null
@@ -1,295 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Create/Delete cluster peer relations on ONTAP
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_cluster_peer
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified cluster peer should exist or not.
- default: present
- source_intercluster_lifs:
- description:
- - List of intercluster addresses of the source cluster.
- - Used as peer-addresses in destination cluster.
- - All these intercluster lifs should belong to the source cluster.
- version_added: "2.8"
- aliases:
- - source_intercluster_lif
- dest_intercluster_lifs:
- description:
- - List of intercluster addresses of the destination cluster.
- - Used as peer-addresses in source cluster.
- - All these intercluster lifs should belong to the destination cluster.
- version_added: "2.8"
- aliases:
- - dest_intercluster_lif
- passphrase:
- description:
- - The arbitrary passphrase that matches the one given to the peer cluster.
- source_cluster_name:
- description:
- - The name of the source cluster name in the peer relation to be deleted.
- dest_cluster_name:
- description:
- - The name of the destination cluster name in the peer relation to be deleted.
- - Required for delete
- dest_hostname:
- description:
- - Destination cluster IP or hostname which needs to be peered
- - Required to complete the peering process at destination cluster.
- required: True
- dest_username:
- description:
- - Destination username.
- - Optional if this is same as source username.
- dest_password:
- description:
- - Destination password.
- - Optional if this is same as source password.
-short_description: NetApp ONTAP Manage Cluster peering
-version_added: "2.7"
-'''
-
-EXAMPLES = """
-
- - name: Create cluster peer
- na_ontap_cluster_peer:
- state: present
- source_intercluster_lifs: 1.2.3.4,1.2.3.5
- dest_intercluster_lifs: 1.2.3.6,1.2.3.7
- passphrase: XXXX
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- dest_hostname: "{{ dest_netapp_hostname }}"
-
- - name: Delete cluster peer
- na_ontap_cluster_peer:
- state: absent
- source_cluster_name: test-source-cluster
- dest_cluster_name: test-dest-cluster
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- dest_hostname: "{{ dest_netapp_hostname }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPClusterPeer(object):
- """
- Class with cluster peer methods
- """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- source_intercluster_lifs=dict(required=False, type='list', aliases=['source_intercluster_lif']),
- dest_intercluster_lifs=dict(required=False, type='list', aliases=['dest_intercluster_lif']),
- passphrase=dict(required=False, type='str', no_log=True),
- dest_hostname=dict(required=True, type='str'),
- dest_username=dict(required=False, type='str'),
- dest_password=dict(required=False, type='str', no_log=True),
- source_cluster_name=dict(required=False, type='str'),
- dest_cluster_name=dict(required=False, type='str')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_together=[['source_intercluster_lifs', 'dest_intercluster_lifs']],
- required_if=[('state', 'absent', ['source_cluster_name', 'dest_cluster_name'])],
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- # set destination server connection
- self.module.params['hostname'] = self.parameters['dest_hostname']
- if self.parameters.get('dest_username'):
- self.module.params['username'] = self.parameters['dest_username']
- if self.parameters.get('dest_password'):
- self.module.params['password'] = self.parameters['dest_password']
- self.dest_server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- # reset to source host connection for asup logs
- self.module.params['hostname'] = self.parameters['hostname']
-
- def cluster_peer_get_iter(self, cluster):
- """
- Compose NaElement object to query current source cluster using peer-cluster-name and peer-addresses parameters
- :param cluster: type of cluster (source or destination)
- :return: NaElement object for cluster-get-iter with query
- """
- cluster_peer_get = netapp_utils.zapi.NaElement('cluster-peer-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- cluster_peer_info = netapp_utils.zapi.NaElement('cluster-peer-info')
- if cluster == 'source':
- peer_lifs, peer_cluster = 'dest_intercluster_lifs', 'dest_cluster_name'
- else:
- peer_lifs, peer_cluster = 'source_intercluster_lifs', 'source_cluster_name'
- if self.parameters.get(peer_lifs):
- peer_addresses = netapp_utils.zapi.NaElement('peer-addresses')
- for peer in self.parameters.get(peer_lifs):
- peer_addresses.add_new_child('remote-inet-address', peer)
- cluster_peer_info.add_child_elem(peer_addresses)
- if self.parameters.get(peer_cluster):
- cluster_peer_info.add_new_child('cluster-name', self.parameters[peer_cluster])
- query.add_child_elem(cluster_peer_info)
- cluster_peer_get.add_child_elem(query)
- return cluster_peer_get
-
- def cluster_peer_get(self, cluster):
- """
- Get current cluster peer info
- :param cluster: type of cluster (source or destination)
- :return: Dictionary of current cluster peer details if query successful, else return None
- """
- cluster_peer_get_iter = self.cluster_peer_get_iter(cluster)
- result, cluster_info = None, dict()
- if cluster == 'source':
- server = self.server
- else:
- server = self.dest_server
- try:
- result = server.invoke_successfully(cluster_peer_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching cluster peer %s: %s'
- % (self.parameters['dest_cluster_name'], to_native(error)),
- exception=traceback.format_exc())
- # return cluster peer details
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) >= 1:
- cluster_peer_info = result.get_child_by_name('attributes-list').get_child_by_name('cluster-peer-info')
- cluster_info['cluster_name'] = cluster_peer_info.get_child_content('cluster-name')
- peers = cluster_peer_info.get_child_by_name('peer-addresses')
- cluster_info['peer-addresses'] = [peer.get_content() for peer in peers.get_children()]
- return cluster_info
- return None
-
- def cluster_peer_delete(self, cluster):
- """
- Delete a cluster peer on source or destination
- For source cluster, peer cluster-name = destination cluster name and vice-versa
- :param cluster: type of cluster (source or destination)
- :return:
- """
- if cluster == 'source':
- server, peer_cluster_name = self.server, self.parameters['dest_cluster_name']
- else:
- server, peer_cluster_name = self.dest_server, self.parameters['source_cluster_name']
- cluster_peer_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'cluster-peer-delete', **{'cluster-name': peer_cluster_name})
- try:
- server.invoke_successfully(cluster_peer_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting cluster peer %s: %s'
- % (peer_cluster_name, to_native(error)),
- exception=traceback.format_exc())
-
- def cluster_peer_create(self, cluster):
- """
- Create a cluster peer on source or destination
- For source cluster, peer addresses = destination inter-cluster LIFs and vice-versa
- :param cluster: type of cluster (source or destination)
- :return: None
- """
- cluster_peer_create = netapp_utils.zapi.NaElement.create_node_with_children('cluster-peer-create')
- if self.parameters.get('passphrase') is not None:
- cluster_peer_create.add_new_child('passphrase', self.parameters['passphrase'])
- peer_addresses = netapp_utils.zapi.NaElement('peer-addresses')
- if cluster == 'source':
- server, peer_address = self.server, self.parameters['dest_intercluster_lifs']
- else:
- server, peer_address = self.dest_server, self.parameters['source_intercluster_lifs']
- for each in peer_address:
- peer_addresses.add_new_child('remote-inet-address', each)
- cluster_peer_create.add_child_elem(peer_addresses)
- try:
- server.invoke_successfully(cluster_peer_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating cluster peer %s: %s'
- % (peer_address, to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Apply action to cluster peer
- :return: None
- """
- self.asup_log_for_cserver("na_ontap_cluster_peer")
- source = self.cluster_peer_get('source')
- destination = self.cluster_peer_get('destination')
- source_action = self.na_helper.get_cd_action(source, self.parameters)
- destination_action = self.na_helper.get_cd_action(destination, self.parameters)
- self.na_helper.changed = False
- # create only if expected cluster peer relation is not present on both source and destination clusters
- if source_action == 'create' and destination_action == 'create':
- self.cluster_peer_create('source')
- self.cluster_peer_create('destination')
- self.na_helper.changed = True
- # delete peer relation in cluster where relation is present
- else:
- if source_action == 'delete':
- self.cluster_peer_delete('source')
- self.na_helper.changed = True
- if destination_action == 'delete':
- self.cluster_peer_delete('destination')
- self.na_helper.changed = True
-
- self.module.exit_json(changed=self.na_helper.changed)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
-
-def main():
- """
- Execute action
- :return: None
- """
- community_obj = NetAppONTAPClusterPeer()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_command.py b/lib/ansible/modules/storage/netapp/na_ontap_command.py
deleted file mode 100644
index 60ff63b86a..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_command.py
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/python
-'''
-# (c) 2018, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-'''
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - "Run system-cli commands on ONTAP"
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_command
-short_description: NetApp ONTAP Run any cli command, the username provided needs to have console login permission.
-version_added: "2.7"
-options:
- command:
- description:
- - a comma separated list containing the command and arguments.
- required: true
- privilege:
- description:
- - privilege level at which to run the command.
- choices: ['admin', 'advanced']
- default: admin
- version_added: "2.8"
- return_dict:
- description:
- - returns a parsesable dictionary instead of raw XML output
- type: bool
- default: false
- version_added: "2.9"
-'''
-
-EXAMPLES = """
- - name: run ontap cli command
- na_ontap_command:
- hostname: "{{ hostname }}"
- username: "{{ admin username }}"
- password: "{{ admin password }}"
- command: ['version']
-
- - name: run ontap cli command
- na_ontap_command:
- hostname: "{{ hostname }}"
- username: "{{ admin username }}"
- password: "{{ admin password }}"
- command: ['network', 'interface', 'show']
- privilege: 'admin'
- return_dict: true
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPCommand(object):
- ''' calls a CLI command '''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- command=dict(required=True, type='list'),
- privilege=dict(required=False, type='str', choices=['admin', 'advanced'], default='admin'),
- return_dict=dict(required=False, type='bool', default=False)
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- parameters = self.module.params
- # set up state variables
- self.command = parameters['command']
- self.privilege = parameters['privilege']
- self.return_dict = parameters['return_dict']
-
- self.result_dict = dict()
- self.result_dict['status'] = ""
- self.result_dict['result_value'] = 0
- self.result_dict['invoked_command'] = " ".join(self.command)
- self.result_dict['stdout'] = ""
- self.result_dict['stdout_lines'] = []
- self.result_dict['xml_dict'] = dict()
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
- def run_command(self):
- ''' calls the ZAPI '''
- self.asup_log_for_cserver("na_ontap_command: " + str(self.command))
- command_obj = netapp_utils.zapi.NaElement("system-cli")
-
- args_obj = netapp_utils.zapi.NaElement("args")
- if self.return_dict:
- args_obj.add_new_child('arg', 'set')
- args_obj.add_new_child('arg', '-showseparator')
- args_obj.add_new_child('arg', '"###"')
- args_obj.add_new_child('arg', ';')
- for arg in self.command:
- args_obj.add_new_child('arg', arg)
- command_obj.add_child_elem(args_obj)
- command_obj.add_new_child('priv', self.privilege)
-
- try:
- output = self.server.invoke_successfully(command_obj, True)
- if self.return_dict:
- # Parseable dict output
- retval = self.parse_xml_to_dict(output.to_string())
- else:
- # Raw XML output
- retval = output.to_string()
-
- return retval
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error running command %s: %s' %
- (self.command, to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- ''' calls the command and returns raw output '''
- changed = True
- output = self.run_command()
- self.module.exit_json(changed=changed, msg=output)
-
- def parse_xml_to_dict(self, xmldata):
- '''Parse raw XML from system-cli and create an Ansible parseable dictionary'''
- xml_import_ok = True
- xml_parse_ok = True
-
- try:
- import xml.parsers.expat
- except ImportError:
- self.result_dict['status'] = "XML parsing failed. Cannot import xml.parsers.expat!"
- self.result_dict['stdout'] = str(xmldata)
- xml_import_ok = False
-
- if xml_import_ok:
- xml_str = xmldata.decode('utf-8').replace('\n', '---')
- xml_parser = xml.parsers.expat.ParserCreate()
- xml_parser.StartElementHandler = self._start_element
- xml_parser.CharacterDataHandler = self._char_data
- xml_parser.EndElementHandler = self._end_element
-
- try:
- xml_parser.Parse(xml_str)
- except xml.parsers.expat.ExpatError as errcode:
- self.result_dict['status'] = "XML parsing failed: " + str(errcode)
- self.result_dict['stdout'] = str(xmldata)
- xml_parse_ok = False
-
- if xml_parse_ok:
- self.result_dict['status'] = self.result_dict['xml_dict']['results']['attrs']['status']
- stdout_string = self._format_escaped_data(self.result_dict['xml_dict']['cli-output']['data'])
- self.result_dict['stdout'] = stdout_string
- for line in stdout_string.split('\n'):
- stripped_line = line.strip()
- if len(stripped_line) > 1:
- self.result_dict['stdout_lines'].append(stripped_line)
- self.result_dict['xml_dict']['cli-output']['data'] = stdout_string
- self.result_dict['result_value'] = int(str(self.result_dict['xml_dict']['cli-result-value']['data']).replace("'", ""))
-
- return self.result_dict
-
- def _start_element(self, name, attrs):
- ''' Start XML element '''
- self.result_dict['xml_dict'][name] = dict()
- self.result_dict['xml_dict'][name]['attrs'] = attrs
- self.result_dict['xml_dict'][name]['data'] = ""
- self.result_dict['xml_dict']['active_element'] = name
- self.result_dict['xml_dict']['last_element'] = ""
-
- def _char_data(self, data):
- ''' Dump XML element data '''
- self.result_dict['xml_dict'][str(self.result_dict['xml_dict']['active_element'])]['data'] = repr(data)
-
- def _end_element(self, name):
- self.result_dict['xml_dict']['last_element'] = name
- self.result_dict['xml_dict']['active_element'] = ""
-
- @classmethod
- def _format_escaped_data(cls, datastring):
- ''' replace helper escape sequences '''
- formatted_string = datastring.replace('------', '---').replace('---', '\n').replace("###", " ").strip()
- retval_string = ""
- for line in formatted_string.split('\n'):
- stripped_line = line.strip()
- if len(stripped_line) > 1:
- retval_string += stripped_line + "\n"
- return retval_string
-
-
-def main():
- """
- Execute action from playbook
- """
- command = NetAppONTAPCommand()
- command.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_disks.py b/lib/ansible/modules/storage/netapp/na_ontap_disks.py
deleted file mode 100644
index 5e719fa3ea..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_disks.py
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_disks
-
-short_description: NetApp ONTAP Assign disks to nodes
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.7'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Assign all or part of disks to nodes.
-
-options:
-
- node:
- required: true
- description:
- - It specifies the node to assign all visible unowned disks.
-
- disk_count:
- required: false
- type: int
- description:
- - Total number of disks a node should own
- version_added: '2.9'
-'''
-
-EXAMPLES = """
-- name: Assign unowned disks
- na_ontap_disks:
- node: cluster-01
- hostname: "{{ hostname }}"
- username: "{{ admin username }}"
- password: "{{ admin password }}"
-
-- name: Assign specified total disks
- na_ontap_disks:
- node: cluster-01
- disk_count: 56
- hostname: "{{ hostname }}"
- username: "{{ admin username }}"
- password: "{{ admin password }}"
-"""
-
-RETURN = """
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapDisks(object):
- ''' object initialize and class methods '''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- node=dict(required=True, type='str'),
- disk_count=dict(required=False, type='int')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def get_unassigned_disk_count(self):
- """
- Check for free disks
- """
- disk_iter = netapp_utils.zapi.NaElement('storage-disk-get-iter')
- disk_storage_info = netapp_utils.zapi.NaElement('storage-disk-info')
- disk_raid_info = netapp_utils.zapi.NaElement('disk-raid-info')
- disk_raid_info.add_new_child('container-type', 'unassigned')
- disk_storage_info.add_child_elem(disk_raid_info)
-
- disk_query = netapp_utils.zapi.NaElement('query')
- disk_query.add_child_elem(disk_storage_info)
-
- disk_iter.add_child_elem(disk_query)
-
- try:
- result = self.server.invoke_successfully(disk_iter, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting disk information: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
- return int(result.get_child_content('num-records'))
-
- def get_owned_disk_count(self):
- """
- Check for owned disks
- """
- disk_iter = netapp_utils.zapi.NaElement('storage-disk-get-iter')
- disk_storage_info = netapp_utils.zapi.NaElement('storage-disk-info')
- disk_ownership_info = netapp_utils.zapi.NaElement('disk-ownership-info')
- disk_ownership_info.add_new_child('home-node-name', self.parameters['node'])
- disk_storage_info.add_child_elem(disk_ownership_info)
-
- disk_query = netapp_utils.zapi.NaElement('query')
- disk_query.add_child_elem(disk_storage_info)
-
- disk_iter.add_child_elem(disk_query)
-
- try:
- result = self.server.invoke_successfully(disk_iter, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting disk information: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
- return int(result.get_child_content('num-records'))
-
- def disk_assign(self, needed_disks):
- """
- Set node as disk owner.
- """
- if needed_disks > 0:
- assign_disk = netapp_utils.zapi.NaElement.create_node_with_children(
- 'disk-sanown-assign', **{'owner': self.parameters['node'],
- 'disk-count': str(needed_disks)})
- else:
- assign_disk = netapp_utils.zapi.NaElement.create_node_with_children(
- 'disk-sanown-assign', **{'node-name': self.parameters['node'],
- 'all': 'true'})
- try:
- self.server.invoke_successfully(assign_disk,
- enable_tunneling=True)
- return True
- except netapp_utils.zapi.NaApiError as error:
- if to_native(error.code) == "13001":
- # Error 13060 denotes aggregate is already online
- return False
- else:
- self.module.fail_json(msg='Error assigning disks %s' %
- (to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- '''Apply action to disks'''
- changed = False
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_disks", cserver)
-
- # check if anything needs to be changed (add/delete/update)
- unowned_disks = self.get_unassigned_disk_count()
- owned_disks = self.get_owned_disk_count()
- if 'disk_count' in self.parameters:
- if self.parameters['disk_count'] < owned_disks:
- self.module.fail_json(msg="Fewer disks than are currently owned was requested. "
- "This module does not do any disk removing. "
- "All disk removing will need to be done manually.")
- if self.parameters['disk_count'] > owned_disks + unowned_disks:
- self.module.fail_json(msg="Not enough unowned disks remain to fulfill request")
- if unowned_disks >= 1:
- if 'disk_count' in self.parameters:
- if self.parameters['disk_count'] > owned_disks:
- needed_disks = self.parameters['disk_count'] - owned_disks
- self.disk_assign(needed_disks)
- changed = True
- else:
- self.disk_assign(0)
- changed = True
- self.module.exit_json(changed=changed)
-
-
-def main():
- ''' Create object and call apply '''
- obj_aggr = NetAppOntapDisks()
- obj_aggr.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_dns.py b/lib/ansible/modules/storage/netapp/na_ontap_dns.py
deleted file mode 100644
index afadcaec03..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_dns.py
+++ /dev/null
@@ -1,294 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_dns
-short_description: NetApp ONTAP Create, delete, modify DNS servers.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.7'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create, delete, modify DNS servers.
-options:
- state:
- description:
- - Whether the DNS servers should be enabled for the given vserver.
- choices: ['present', 'absent']
- default: present
-
- vserver:
- description:
- - The name of the vserver to use.
- required: true
-
- domains:
- description:
- - List of DNS domains such as 'sales.bar.com'. The first domain is the one that the Vserver belongs to.
-
- nameservers:
- description:
- - List of IPv4 addresses of name servers such as '123.123.123.123'.
-
- skip_validation:
- type: bool
- description:
- - By default, all nameservers are checked to validate they are available to resolve.
- - If you DNS servers are not yet installed or momentarily not available, you can set this option to 'true'
- - to bypass the check for all servers specified in nameservers field.
- version_added: '2.8'
-'''
-
-EXAMPLES = """
- - name: create DNS
- na_ontap_dns:
- state: present
- hostname: "{{hostname}}"
- username: "{{username}}"
- password: "{{password}}"
- vserver: "{{vservername}}"
- domains: sales.bar.com
- nameservers: 10.193.0.250,10.192.0.250
- skip_validation: true
-"""
-
-RETURN = """
-
-"""
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils.netapp import OntapRestAPI
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapDns(object):
- """
- Enable and Disable dns
- """
-
- def __init__(self):
- self.use_rest = False
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- domains=dict(required=False, type='list'),
- nameservers=dict(required=False, type='list'),
- skip_validation=dict(required=False, type='bool')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[('state', 'present', ['domains', 'nameservers'])],
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- # REST API should be used for ONTAP 9.6 or higher, ZAPI for lower version
- self.restApi = OntapRestAPI(self.module)
- # some attributes are not supported in earlier REST implementation
- unsupported_rest_properties = ['skip_validation']
- used_unsupported_rest_properties = [x for x in unsupported_rest_properties if x in self.parameters]
- self.use_rest, error = self.restApi.is_rest(used_unsupported_rest_properties)
-
- if error is not None:
- self.module.fail_json(msg=error)
-
- if not self.use_rest:
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
- return
-
- def create_dns(self):
- """
- Create DNS server
- :return: none
- """
- if self.use_rest:
- api = 'name-services/dns'
- params = {}
- params['domains'] = self.parameters['domains']
- params['servers'] = self.parameters['nameservers']
- params['svm'] = {'name': self.parameters['vserver']}
- message, error = self.restApi.post(api, params)
- if error:
- self.module.fail_json(msg=error)
- else:
- dns = netapp_utils.zapi.NaElement('net-dns-create')
- nameservers = netapp_utils.zapi.NaElement('name-servers')
- domains = netapp_utils.zapi.NaElement('domains')
- for each in self.parameters['nameservers']:
- ip_address = netapp_utils.zapi.NaElement('ip-address')
- ip_address.set_content(each)
- nameservers.add_child_elem(ip_address)
- dns.add_child_elem(nameservers)
- for each in self.parameters['domains']:
- domain = netapp_utils.zapi.NaElement('string')
- domain.set_content(each)
- domains.add_child_elem(domain)
- dns.add_child_elem(domains)
- if self.parameters.get('skip_validation'):
- validation = netapp_utils.zapi.NaElement('skip-config-validation')
- validation.set_content(str(self.parameters['skip_validation']))
- dns.add_child_elem(validation)
- try:
- self.server.invoke_successfully(dns, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating dns: %s' %
- (to_native(error)),
- exception=traceback.format_exc())
-
- def destroy_dns(self, dns_attrs):
- """
- Destroys an already created dns
- :return:
- """
- if self.use_rest:
- uuid = dns_attrs['records'][0]['svm']['uuid']
- api = 'name-services/dns/' + uuid
- data = None
- message, error = self.restApi.delete(api, data)
- if error:
- self.module.fail_json(msg=error)
- else:
- try:
- self.server.invoke_successfully(netapp_utils.zapi.NaElement('net-dns-destroy'), True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error destroying dns %s' %
- (to_native(error)),
- exception=traceback.format_exc())
-
- def get_dns(self):
- if self.use_rest:
- api = "name-services/dns"
- params = {'fields': 'domains,servers,svm',
- "svm.name": self.parameters['vserver']}
- message, error = self.restApi.get(api, params)
- if error:
- self.module.fail_json(msg=error)
- if len(message.keys()) == 0:
- message = None
- elif 'records' in message and len(message['records']) == 0:
- message = None
- elif 'records' not in message or len(message['records']) != 1:
- error = "Unexpected response from %s: %s" % (api, repr(message))
- self.module.fail_json(msg=error)
- return message
- else:
- dns_obj = netapp_utils.zapi.NaElement('net-dns-get')
- try:
- result = self.server.invoke_successfully(dns_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- if to_native(error.code) == "15661":
- # 15661 is object not found
- return None
- else:
- self.module.fail_json(msg=to_native(
- error), exception=traceback.format_exc())
-
- # read data for modify
- attrs = dict()
- attributes = result.get_child_by_name('attributes')
- dns_info = attributes.get_child_by_name('net-dns-info')
- nameservers = dns_info.get_child_by_name('name-servers')
- attrs['nameservers'] = [each.get_content() for each in nameservers.get_children()]
- domains = dns_info.get_child_by_name('domains')
- attrs['domains'] = [each.get_content() for each in domains.get_children()]
- attrs['skip_validation'] = dns_info.get_child_by_name('skip-config-validation')
- return attrs
-
- def modify_dns(self, dns_attrs):
- if self.use_rest:
- changed = False
- params = {}
- if dns_attrs['records'][0]['servers'] != self.parameters['nameservers']:
- changed = True
- params['servers'] = self.parameters['nameservers']
- if dns_attrs['records'][0]['domains'] != self.parameters['domains']:
- changed = True
- params['domains'] = self.parameters['domains']
- if changed:
- uuid = dns_attrs['records'][0]['svm']['uuid']
- api = "name-services/dns/" + uuid
- message, error = self.restApi.patch(api, params)
- if error:
- self.module.fail_json(msg=error)
-
- else:
- changed = False
- dns = netapp_utils.zapi.NaElement('net-dns-modify')
- if dns_attrs['nameservers'] != self.parameters['nameservers']:
- changed = True
- nameservers = netapp_utils.zapi.NaElement('name-servers')
- for each in self.parameters['nameservers']:
- ip_address = netapp_utils.zapi.NaElement('ip-address')
- ip_address.set_content(each)
- nameservers.add_child_elem(ip_address)
- dns.add_child_elem(nameservers)
- if dns_attrs['domains'] != self.parameters['domains']:
- changed = True
- domains = netapp_utils.zapi.NaElement('domains')
- for each in self.parameters['domains']:
- domain = netapp_utils.zapi.NaElement('string')
- domain.set_content(each)
- domains.add_child_elem(domain)
- dns.add_child_elem(domains)
- if changed:
- if self.parameters.get('skip_validation'):
- validation = netapp_utils.zapi.NaElement('skip-config-validation')
- validation.set_content(str(self.parameters['skip_validation']))
- dns.add_child_elem(validation)
- try:
- self.server.invoke_successfully(dns, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying dns %s' %
- (to_native(error)), exception=traceback.format_exc())
- return changed
-
- def apply(self):
- # asup logging
- if not self.use_rest:
- netapp_utils.ems_log_event("na_ontap_dns", self.server)
- dns_attrs = self.get_dns()
- changed = False
- if self.parameters['state'] == 'present':
- if dns_attrs is not None:
- changed = self.modify_dns(dns_attrs)
- else:
- self.create_dns()
- changed = True
- else:
- if dns_attrs is not None:
- self.destroy_dns(dns_attrs)
- changed = True
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Create, Delete, Modify DNS servers.
- """
- obj = NetAppOntapDns()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_export_policy.py b/lib/ansible/modules/storage/netapp/na_ontap_export_policy.py
deleted file mode 100644
index cc6b7d613e..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_export_policy.py
+++ /dev/null
@@ -1,231 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-module: na_ontap_export_policy
-short_description: NetApp ONTAP manage export-policy
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create or destroy or rename export-policies on ONTAP
-options:
- state:
- description:
- - Whether the specified export policy should exist or not.
- choices: ['present', 'absent']
- default: present
- name:
- description:
- - The name of the export-policy to manage.
- required: true
- from_name:
- description:
- - The name of the export-policy to be renamed.
- version_added: '2.7'
- vserver:
- description:
- - Name of the vserver to use.
-'''
-
-EXAMPLES = """
- - name: Create Export Policy
- na_ontap_export_policy:
- state: present
- name: ansiblePolicyName
- vserver: vs_hack
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Rename Export Policy
- na_ontap_export_policy:
- action: present
- from_name: ansiblePolicyName
- vserver: vs_hack
- name: newPolicyName
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Delete Export Policy
- na_ontap_export_policy:
- state: absent
- name: ansiblePolicyName
- vserver: vs_hack
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPExportPolicy(object):
- """
- Class with export policy methods
- """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- from_name=dict(required=False, type='str', default=None),
- vserver=dict(required=False, type='str')
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('state', 'present', ['vserver'])
- ],
- supports_check_mode=True
- )
- parameters = self.module.params
- # set up state variables
- self.state = parameters['state']
- self.name = parameters['name']
- self.from_name = parameters['from_name']
- self.vserver = parameters['vserver']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver)
-
- def get_export_policy(self, name=None):
- """
- Return details about the export-policy
- :param:
- name : Name of the export-policy
- :return: Details about the export-policy. None if not found.
- :rtype: dict
- """
- if name is None:
- name = self.name
- export_policy_iter = netapp_utils.zapi.NaElement('export-policy-get-iter')
- export_policy_info = netapp_utils.zapi.NaElement('export-policy-info')
- export_policy_info.add_new_child('policy-name', name)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(export_policy_info)
- export_policy_iter.add_child_elem(query)
- result = self.server.invoke_successfully(export_policy_iter, True)
- return_value = None
- # check if query returns the expected export-policy
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
-
- export_policy = result.get_child_by_name('attributes-list').get_child_by_name('export-policy-info').get_child_by_name('policy-name')
- return_value = {
- 'policy-name': export_policy
- }
- return return_value
-
- def create_export_policy(self):
- """
- Creates an export policy
- """
- export_policy_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'export-policy-create', **{'policy-name': self.name})
- try:
- self.server.invoke_successfully(export_policy_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating export-policy %s: %s'
- % (self.name, to_native(error)),
- exception=traceback.format_exc())
-
- def delete_export_policy(self):
- """
- Delete export-policy
- """
- export_policy_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'export-policy-destroy', **{'policy-name': self.name, })
- try:
- self.server.invoke_successfully(export_policy_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting export-policy %s: %s'
- % (self.name,
- to_native(error)), exception=traceback.format_exc())
-
- def rename_export_policy(self):
- """
- Rename the export-policy.
- """
- export_policy_rename = netapp_utils.zapi.NaElement.create_node_with_children(
- 'export-policy-rename', **{'policy-name': self.from_name,
- 'new-policy-name': self.name})
- try:
- self.server.invoke_successfully(export_policy_rename,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error renaming export-policy %s:%s'
- % (self.name, to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Apply action to export-policy
- """
- changed = False
- export_policy_exists = False
- netapp_utils.ems_log_event("na_ontap_export_policy", self.server)
- rename_flag = False
- export_policy_details = self.get_export_policy()
- if export_policy_details:
- export_policy_exists = True
- if self.state == 'absent': # delete
- changed = True
- else:
- if self.state == 'present': # create or rename
- if self.from_name is not None:
- if self.get_export_policy(self.from_name):
- changed = True
- rename_flag = True
- else:
- self.module.fail_json(msg='Error renaming export-policy %s: does not exists' % self.from_name)
- else: # create
- changed = True
- if changed:
- if self.module.check_mode:
- pass
- else:
- if self.state == 'present': # execute create or rename_export_policy
- if rename_flag:
- self.rename_export_policy()
- else:
- self.create_export_policy()
- elif self.state == 'absent': # execute delete
- self.delete_export_policy()
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Execute action
- """
- export_policy = NetAppONTAPExportPolicy()
- export_policy.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_export_policy_rule.py b/lib/ansible/modules/storage/netapp/na_ontap_export_policy_rule.py
deleted file mode 100644
index 831975f288..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_export_policy_rule.py
+++ /dev/null
@@ -1,431 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_export_policy_rule
-
-short_description: NetApp ONTAP manage export policy rules
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create or delete or modify export rules in ONTAP
-
-options:
- state:
- description:
- - Whether the specified export policy rule should exist or not.
- required: false
- choices: ['present', 'absent']
- default: present
-
- name:
- description:
- - The name of the export rule to manage.
- required: True
- aliases:
- - policy_name
-
- client_match:
- description:
- - List of Client Match host names, IP Addresses, Netgroups, or Domains
- - If rule_index is not provided, client_match is used as a key to fetch current rule to determine create,delete,modify actions.
- If a rule with provided client_match exists, a new rule will not be created, but the existing rule will be modified or deleted.
- If a rule with provided client_match doesn't exist, a new rule will be created if state is present.
-
- ro_rule:
- description:
- - List of Read only access specifications for the rule
- choices: ['any','none','never','krb5','krb5i','krb5p','ntlm','sys']
-
- rw_rule:
- description:
- - List of Read Write access specifications for the rule
- choices: ['any','none','never','krb5','krb5i','krb5p','ntlm','sys']
-
- super_user_security:
- description:
- - List of Read Write access specifications for the rule
- choices: ['any','none','never','krb5','krb5i','krb5p','ntlm','sys']
-
- allow_suid:
- description:
- - If 'true', NFS server will honor SetUID bits in SETATTR operation. Default value on creation is 'true'
- type: bool
-
- protocol:
- description:
- - List of Client access protocols.
- - Default value is set to 'any' during create.
- choices: [any,nfs,nfs3,nfs4,cifs,flexcache]
-
- rule_index:
- description:
- - rule index of the export policy
-
- vserver:
- description:
- - Name of the vserver to use.
- required: true
-
-'''
-
-EXAMPLES = """
- - name: Create ExportPolicyRule
- na_ontap_export_policy_rule:
- state: present
- name: default123
- vserver: ci_dev
- client_match: 0.0.0.0/0,1.1.1.0/24
- ro_rule: krb5,krb5i
- rw_rule: any
- protocol: nfs,nfs3
- super_user_security: any
- allow_suid: true
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Modify ExportPolicyRule
- na_ontap_export_policy_rule:
- state: present
- name: default123
- rule_index: 100
- client_match: 0.0.0.0/0
- ro_rule: ntlm
- rw_rule: any
- protocol: any
- allow_suid: false
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete ExportPolicyRule
- na_ontap_export_policy_rule:
- state: absent
- name: default123
- rule_index: 100
- vserver: ci_dev
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-"""
-
-RETURN = """
-
-
-"""
-import traceback
-
-import json
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppontapExportRule(object):
- ''' object initialize and class methods '''
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str', aliases=['policy_name']),
- protocol=dict(required=False,
- type='list', default=None,
- choices=['any', 'nfs', 'nfs3', 'nfs4', 'cifs', 'flexcache']),
- client_match=dict(required=False, type='list'),
- ro_rule=dict(required=False,
- type='list', default=None,
- choices=['any', 'none', 'never', 'krb5', 'krb5i', 'krb5p', 'ntlm', 'sys']),
- rw_rule=dict(required=False,
- type='list', default=None,
- choices=['any', 'none', 'never', 'krb5', 'krb5i', 'krb5p', 'ntlm', 'sys']),
- super_user_security=dict(required=False,
- type='list', default=None,
- choices=['any', 'none', 'never', 'krb5', 'krb5i', 'krb5p', 'ntlm', 'sys']),
- allow_suid=dict(required=False, type='bool'),
- rule_index=dict(required=False, type='int'),
- vserver=dict(required=True, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- self.set_playbook_zapi_key_map()
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=self.parameters['vserver'])
-
- def set_playbook_zapi_key_map(self):
- self.na_helper.zapi_string_keys = {
- 'client_match': 'client-match',
- 'name': 'policy-name'
- }
- self.na_helper.zapi_list_keys = {
- 'protocol': ('protocol', 'access-protocol'),
- 'ro_rule': ('ro-rule', 'security-flavor'),
- 'rw_rule': ('rw-rule', 'security-flavor'),
- 'super_user_security': ('super-user-security', 'security-flavor'),
- }
- self.na_helper.zapi_bool_keys = {
- 'allow_suid': 'is-allow-set-uid-enabled'
- }
- self.na_helper.zapi_int_keys = {
- 'rule_index': 'rule-index'
- }
-
- def set_query_parameters(self):
- """
- Return dictionary of query parameters and
- :return:
- """
- query = {
- 'policy-name': self.parameters['name'],
- 'vserver': self.parameters['vserver']
- }
-
- if self.parameters.get('rule_index'):
- query['rule-index'] = self.parameters['rule_index']
- elif self.parameters.get('client_match'):
- query['client-match'] = self.parameters['client_match']
- else:
- self.module.fail_json(
- msg="Need to specify at least one of the rule_index and client_match option.")
-
- attributes = {
- 'query': {
- 'export-rule-info': query
- }
- }
- return attributes
-
- def get_export_policy_rule(self):
- """
- Return details about the export policy rule
- :param:
- name : Name of the export_policy
- :return: Details about the export_policy. None if not found.
- :rtype: dict
- """
- current, result = None, None
- rule_iter = netapp_utils.zapi.NaElement('export-rule-get-iter')
- rule_iter.translate_struct(self.set_query_parameters())
- try:
- result = self.server.invoke_successfully(rule_iter, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting export policy rule %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- if result is not None and \
- result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- current = dict()
- rule_info = result.get_child_by_name('attributes-list').get_child_by_name('export-rule-info')
- for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
- current[item_key] = rule_info.get_child_content(zapi_key)
- for item_key, zapi_key in self.na_helper.zapi_bool_keys.items():
- current[item_key] = self.na_helper.get_value_for_bool(from_zapi=True,
- value=rule_info[zapi_key])
- for item_key, zapi_key in self.na_helper.zapi_int_keys.items():
- current[item_key] = self.na_helper.get_value_for_int(from_zapi=True,
- value=rule_info[zapi_key])
- for item_key, zapi_key in self.na_helper.zapi_list_keys.items():
- parent, dummy = zapi_key
- current[item_key] = self.na_helper.get_value_for_list(from_zapi=True,
- zapi_parent=rule_info.get_child_by_name(parent))
- current['num_records'] = int(result.get_child_content('num-records'))
- if not self.parameters.get('rule_index'):
- self.parameters['rule_index'] = current['rule_index']
- return current
-
- def get_export_policy(self):
- """
- Return details about the export-policy
- :param:
- name : Name of the export-policy
-
- :return: Details about the export-policy. None if not found.
- :rtype: dict
- """
- export_policy_iter = netapp_utils.zapi.NaElement('export-policy-get-iter')
- attributes = {
- 'query': {
- 'export-policy-info': {
- 'policy-name': self.parameters['name'],
- 'vserver': self.parameters['vserver']
- }
- }
- }
-
- export_policy_iter.translate_struct(attributes)
- try:
- result = self.server.invoke_successfully(export_policy_iter, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting export policy %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) == 1:
- return result
-
- return None
-
- def add_parameters_for_create_or_modify(self, na_element_object, values):
- """
- Add children node for create or modify NaElement object
- :param na_element_object: modify or create NaElement object
- :param values: dictionary of cron values to be added
- :return: None
- """
- for key in values:
- if key in self.na_helper.zapi_string_keys:
- zapi_key = self.na_helper.zapi_string_keys.get(key)
- na_element_object[zapi_key] = values[key]
- elif key in self.na_helper.zapi_list_keys:
- parent_key, child_key = self.na_helper.zapi_list_keys.get(key)
- na_element_object.add_child_elem(self.na_helper.get_value_for_list(from_zapi=False,
- zapi_parent=parent_key,
- zapi_child=child_key,
- data=values[key]))
- elif key in self.na_helper.zapi_int_keys:
- zapi_key = self.na_helper.zapi_int_keys.get(key)
- na_element_object[zapi_key] = self.na_helper.get_value_for_int(from_zapi=False,
- value=values[key])
- elif key in self.na_helper.zapi_bool_keys:
- zapi_key = self.na_helper.zapi_bool_keys.get(key)
- na_element_object[zapi_key] = self.na_helper.get_value_for_bool(from_zapi=False,
- value=values[key])
-
- def create_export_policy_rule(self):
- """
- create rule for the export policy.
- """
- for key in ['client_match', 'ro_rule', 'rw_rule']:
- if self.parameters.get(key) is None:
- self.module.fail_json(msg='Error: Missing required param for creating export policy rule %s' % key)
- export_rule_create = netapp_utils.zapi.NaElement('export-rule-create')
- self.add_parameters_for_create_or_modify(export_rule_create, self.parameters)
- try:
- self.server.invoke_successfully(export_rule_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating export policy rule %s: %s'
- % (self.parameters['name'], to_native(error)), exception=traceback.format_exc())
-
- def create_export_policy(self):
- """
- Creates an export policy
- """
- export_policy_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'export-policy-create', **{'policy-name': self.parameters['name']})
- try:
- self.server.invoke_successfully(export_policy_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating export-policy %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_export_policy_rule(self, rule_index):
- """
- delete rule for the export policy.
- """
- export_rule_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'export-rule-destroy', **{'policy-name': self.parameters['name'],
- 'rule-index': str(rule_index)})
-
- try:
- self.server.invoke_successfully(export_rule_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting export policy rule %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_export_policy_rule(self, params):
- '''
- Modify an existing export policy rule
- :param params: dict() of attributes with desired values
- :return: None
- '''
- export_rule_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'export-rule-modify', **{'policy-name': self.parameters['name'],
- 'rule-index': str(self.parameters['rule_index'])})
- self.add_parameters_for_create_or_modify(export_rule_modify, params)
- try:
- self.server.invoke_successfully(export_rule_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying allow_suid %s: %s'
- % (self.parameters['allow_suid'], to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- netapp_utils.ems_log_event("na_ontap_export_policy_rules", self.server)
-
- def apply(self):
- ''' Apply required action from the play'''
- self.autosupport_log()
- # convert client_match list to comma-separated string
- if self.parameters.get('client_match') is not None:
- self.parameters['client_match'] = ','.join(self.parameters['client_match'])
- self.parameters['client_match'] = self.parameters['client_match'].replace(' ', '')
-
- current, modify = self.get_export_policy_rule(), None
- action = self.na_helper.get_cd_action(current, self.parameters)
- if action is None and self.parameters['state'] == 'present':
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- # create export policy (if policy doesn't exist) only when changed=True
- if not self.get_export_policy():
- self.create_export_policy()
- if action == 'create':
- self.create_export_policy_rule()
- elif action == 'delete':
- if current['num_records'] > 1:
- self.module.fail_json(msg='Multiple export policy rules exist.'
- 'Please specify a rule_index to delete')
- self.delete_export_policy_rule(current['rule_index'])
- elif modify:
- self.modify_export_policy_rule(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- ''' Create object and call apply '''
- rule_obj = NetAppontapExportRule()
- rule_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_fcp.py b/lib/ansible/modules/storage/netapp/na_ontap_fcp.py
deleted file mode 100644
index 0969158385..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_fcp.py
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_fcp
-short_description: NetApp ONTAP Start, Stop and Enable FCP services.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.7'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Start, Stop and Enable FCP services.
-options:
- state:
- description:
- - Whether the FCP should be enabled or not.
- choices: ['present', 'absent']
- default: present
-
- status:
- description:
- - Whether the FCP should be up or down
- choices: ['up', 'down']
- default: up
-
- vserver:
- description:
- - The name of the vserver to use.
- required: true
-
-'''
-
-EXAMPLES = """
- - name: create FCP
- na_ontap_fcp:
- state: present
- status: down
- hostname: "{{hostname}}"
- username: "{{username}}"
- password: "{{password}}"
- vserver: "{{vservername}}"
-"""
-
-RETURN = """
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapFCP(object):
- """
- Enable and Disable FCP
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- status=dict(required=False, choices=['up', 'down'], default='up')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
- return
-
- def create_fcp(self):
- """
- Create's and Starts an FCP
- :return: none
- """
- try:
- self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-create'), True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating FCP: %s' %
- (to_native(error)),
- exception=traceback.format_exc())
-
- def start_fcp(self):
- """
- Starts an existing FCP
- :return: none
- """
- try:
- self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-start'), True)
- except netapp_utils.zapi.NaApiError as error:
- # Error 13013 denotes fcp service already started.
- if to_native(error.code) == "13013":
- return None
- else:
- self.module.fail_json(msg='Error starting FCP %s' % (to_native(error)),
- exception=traceback.format_exc())
-
- def stop_fcp(self):
- """
- Steps an Existing FCP
- :return: none
- """
- try:
- self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-stop'), True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error Stopping FCP %s' %
- (to_native(error)),
- exception=traceback.format_exc())
-
- def destroy_fcp(self):
- """
- Destroys an already stopped FCP
- :return:
- """
- try:
- self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-destroy'), True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error destroying FCP %s' %
- (to_native(error)),
- exception=traceback.format_exc())
-
- def get_fcp(self):
- fcp_obj = netapp_utils.zapi.NaElement('fcp-service-get-iter')
- fcp_info = netapp_utils.zapi.NaElement('fcp-service-info')
- fcp_info.add_new_child('vserver', self.parameters['vserver'])
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(fcp_info)
- fcp_obj.add_child_elem(query)
- result = self.server.invoke_successfully(fcp_obj, True)
- # There can only be 1 FCP per vserver. If true, one is set up, else one isn't set up
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) >= 1:
- return True
- else:
- return False
-
- def current_status(self):
- try:
- status = self.server.invoke_successfully(netapp_utils.zapi.NaElement('fcp-service-status'), True)
- return status.get_child_content('is-available') == 'true'
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error destroying FCP: %s' %
- (to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_fcp", cserver)
- exists = self.get_fcp()
- changed = False
- if self.parameters['state'] == 'present':
- if exists:
- if self.parameters['status'] == 'up':
- if not self.current_status():
- self.start_fcp()
- changed = True
- else:
- if self.current_status():
- self.stop_fcp()
- changed = True
- else:
- self.create_fcp()
- if self.parameters['status'] == 'up':
- self.start_fcp()
- elif self.parameters['status'] == 'down':
- self.stop_fcp()
- changed = True
- else:
- if exists:
- if self.current_status():
- self.stop_fcp()
- self.destroy_fcp()
- changed = True
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Start, Stop and Enable FCP services.
- """
- obj = NetAppOntapFCP()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_firewall_policy.py b/lib/ansible/modules/storage/netapp/na_ontap_firewall_policy.py
deleted file mode 100644
index ca58750881..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_firewall_policy.py
+++ /dev/null
@@ -1,351 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_firewall_policy
-short_description: NetApp ONTAP Manage a firewall policy
-version_added: '2.7'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Configure firewall on an ONTAP node and manage firewall policy for an ONTAP SVM
-extends_documentation_fragment:
- - netapp.na_ontap
-requirements:
- - Python package ipaddress. Install using 'pip install ipaddress'
-options:
- state:
- description:
- - Whether to set up a firewall policy or not
- choices: ['present', 'absent']
- default: present
- allow_list:
- description:
- - A list of IPs and masks to use.
- - The host bits of the IP addresses used in this list must be set to 0.
- policy:
- description:
- - A policy name for the firewall policy
- service:
- description:
- - The service to apply the policy to
- choices: ['dns', 'http', 'https', 'ndmp', 'ndmps', 'ntp', 'rsh', 'snmp', 'ssh', 'telnet']
- vserver:
- description:
- - The Vserver to apply the policy to.
- enable:
- description:
- - enable firewall on a node
- choices: ['enable', 'disable']
- logging:
- description:
- - enable logging for firewall on a node
- choices: ['enable', 'disable']
- node:
- description:
- - The node to run the firewall configuration on
-'''
-
-EXAMPLES = """
- - name: create firewall Policy
- na_ontap_firewall_policy:
- state: present
- allow_list: [1.2.3.0/24,1.3.0.0/16]
- policy: pizza
- service: http
- vserver: ci_dev
- hostname: "{{ netapp hostname }}"
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
-
- - name: Modify firewall Policy
- na_ontap_firewall_policy:
- state: present
- allow_list: [1.5.3.0/24]
- policy: pizza
- service: http
- vserver: ci_dev
- hostname: "{{ netapp hostname }}"
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
-
- - name: Destroy firewall Policy
- na_ontap_firewall_policy:
- state: absent
- policy: pizza
- service: http
- vserver: ci_dev
- hostname: "{{ netapp hostname }}"
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
-
- - name: Enable firewall and logging on a node
- na_ontap_firewall_policy:
- node: test-vsim1
- enable: enable
- logging: enable
- hostname: "{{ netapp hostname }}"
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
-
-"""
-
-RETURN = """
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-try:
- import ipaddress
- HAS_IPADDRESS_LIB = True
-except ImportError:
- HAS_IPADDRESS_LIB = False
-
-import sys
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPFirewallPolicy(object):
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- allow_list=dict(required=False, type="list"),
- policy=dict(required=False, type='str'),
- service=dict(required=False, type='str', choices=['dns', 'http', 'https', 'ndmp',
- 'ndmps', 'ntp', 'rsh', 'snmp', 'ssh', 'telnet']),
- vserver=dict(required=False, type="str"),
- enable=dict(required=False, type="str", choices=['enable', 'disable']),
- logging=dict(required=False, type="str", choices=['enable', 'disable']),
- node=dict(required=False, type="str")
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_together=(['policy', 'service', 'vserver'],
- ['enable', 'node']
- ),
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- if HAS_IPADDRESS_LIB is False:
- self.module.fail_json(msg="the python ipaddress lib is required for this module")
- return
-
- def validate_ip_addresses(self):
- '''
- Validate if the given IP address is a network address (i.e. it's host bits are set to 0)
- ONTAP doesn't validate if the host bits are set,
- and hence doesn't add a new address unless the IP is from a different network.
- So this validation allows the module to be idempotent.
- :return: None
- '''
- for ip in self.parameters['allow_list']:
- # create an IPv4 object for current IP address
- if sys.version_info[0] >= 3:
- ip_addr = str(ip)
- else:
- ip_addr = unicode(ip) # pylint: disable=undefined-variable
- # get network address from netmask, throw exception if address is not a network address
- try:
- ipaddress.ip_network(ip_addr)
- except ValueError as exc:
- self.module.fail_json(msg='Error: Invalid IP address value for allow_list parameter.'
- 'Please specify a network address without host bits set: %s'
- % (to_native(exc)))
-
- def get_firewall_policy(self):
- """
- Get a firewall policy
- :return: returns a firewall policy object, or returns False if there are none
- """
- net_firewall_policy_obj = netapp_utils.zapi.NaElement("net-firewall-policy-get-iter")
- attributes = {
- 'query': {
- 'net-firewall-policy-info': self.firewall_policy_attributes()
- }
- }
- net_firewall_policy_obj.translate_struct(attributes)
-
- try:
- result = self.server.invoke_successfully(net_firewall_policy_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error getting firewall policy %s:%s" % (self.parameters['policy'],
- to_native(error)),
- exception=traceback.format_exc())
-
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- attributes_list = result.get_child_by_name('attributes-list')
- policy_info = attributes_list.get_child_by_name('net-firewall-policy-info')
- ips = self.na_helper.get_value_for_list(from_zapi=True,
- zapi_parent=policy_info.get_child_by_name('allow-list'))
- return {
- 'service': policy_info['service'],
- 'allow_list': ips}
- return None
-
- def create_firewall_policy(self):
- """
- Create a firewall policy for given vserver
- :return: None
- """
- net_firewall_policy_obj = netapp_utils.zapi.NaElement("net-firewall-policy-create")
- net_firewall_policy_obj.translate_struct(self.firewall_policy_attributes())
- if self.parameters.get('allow_list'):
- self.validate_ip_addresses()
- net_firewall_policy_obj.add_child_elem(self.na_helper.get_value_for_list(from_zapi=False,
- zapi_parent='allow-list',
- zapi_child='ip-and-mask',
- data=self.parameters['allow_list'])
- )
- try:
- self.server.invoke_successfully(net_firewall_policy_obj, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error creating Firewall Policy: %s" % (to_native(error)), exception=traceback.format_exc())
-
- def destroy_firewall_policy(self):
- """
- Destroy a Firewall Policy from a vserver
- :return: None
- """
- net_firewall_policy_obj = netapp_utils.zapi.NaElement("net-firewall-policy-destroy")
- net_firewall_policy_obj.translate_struct(self.firewall_policy_attributes())
- try:
- self.server.invoke_successfully(net_firewall_policy_obj, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error destroying Firewall Policy: %s" % (to_native(error)), exception=traceback.format_exc())
-
- def modify_firewall_policy(self, modify):
- """
- Modify a firewall Policy on a vserver
- :return: none
- """
- self.validate_ip_addresses()
- net_firewall_policy_obj = netapp_utils.zapi.NaElement("net-firewall-policy-modify")
- net_firewall_policy_obj.translate_struct(self.firewall_policy_attributes())
- net_firewall_policy_obj.add_child_elem(self.na_helper.get_value_for_list(from_zapi=False,
- zapi_parent='allow-list',
- zapi_child='ip-and-mask',
- data=modify['allow_list']))
- try:
- self.server.invoke_successfully(net_firewall_policy_obj, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error modifying Firewall Policy: %s" % (to_native(error)), exception=traceback.format_exc())
-
- def firewall_policy_attributes(self):
- return {
- 'policy': self.parameters['policy'],
- 'service': self.parameters['service'],
- 'vserver': self.parameters['vserver'],
- }
-
- def get_firewall_config_for_node(self):
- """
- Get firewall configuration on the node
- :return: dict() with firewall config details
- """
- if self.parameters.get('logging'):
- if self.parameters.get('node') is None:
- self.module.fail_json(msg='Error: Missing parameter \'node\' to modify firewall logging')
- net_firewall_config_obj = netapp_utils.zapi.NaElement("net-firewall-config-get")
- net_firewall_config_obj.add_new_child('node-name', self.parameters['node'])
- try:
- result = self.server.invoke_successfully(net_firewall_config_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error getting Firewall Configuration: %s" % (to_native(error)),
- exception=traceback.format_exc())
- if result.get_child_by_name('attributes'):
- firewall_info = result['attributes'].get_child_by_name('net-firewall-config-info')
- return {'enable': self.change_status_to_bool(firewall_info.get_child_content('is-enabled'), to_zapi=False),
- 'logging': self.change_status_to_bool(firewall_info.get_child_content('is-logging'), to_zapi=False)}
- return None
-
- def modify_firewall_config(self, modify):
- """
- Modify the configuration of a firewall on node
- :return: None
- """
- net_firewall_config_obj = netapp_utils.zapi.NaElement("net-firewall-config-modify")
- net_firewall_config_obj.add_new_child('node-name', self.parameters['node'])
- if modify.get('enable'):
- net_firewall_config_obj.add_new_child('is-enabled', self.change_status_to_bool(self.parameters['enable']))
- if modify.get('logging'):
- net_firewall_config_obj.add_new_child('is-logging', self.change_status_to_bool(self.parameters['logging']))
- try:
- self.server.invoke_successfully(net_firewall_config_obj, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error modifying Firewall Config: %s" % (to_native(error)),
- exception=traceback.format_exc())
-
- def change_status_to_bool(self, input, to_zapi=True):
- if to_zapi:
- return 'true' if input == 'enable' else 'false'
- else:
- return 'enable' if input == 'true' else 'disable'
-
- def autosupport_log(self):
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_firewall_policy", cserver)
-
- def apply(self):
- self.autosupport_log()
- cd_action, modify, modify_config = None, None, None
- if self.parameters.get('policy'):
- current = self.get_firewall_policy()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action is None and self.parameters['state'] == 'present':
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.parameters.get('node'):
- current_config = self.get_firewall_config_for_node()
- # firewall config for a node is always present, we cannot create or delete a firewall on a node
- modify_config = self.na_helper.get_modified_attributes(current_config, self.parameters)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_firewall_policy()
- elif cd_action == 'delete':
- self.destroy_firewall_policy()
- else:
- if modify:
- self.modify_firewall_policy(modify)
- if modify_config:
- self.modify_firewall_config(modify_config)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Execute action from playbook
- :return: nothing
- """
- cg_obj = NetAppONTAPFirewallPolicy()
- cg_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_firmware_upgrade.py b/lib/ansible/modules/storage/netapp/na_ontap_firmware_upgrade.py
deleted file mode 100644
index dd50060c54..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_firmware_upgrade.py
+++ /dev/null
@@ -1,461 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Update ONTAP service-prosessor firmware
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_firmware_upgrade
-options:
- state:
- description:
- - Whether the specified ONTAP firmware should be upgraded or not.
- default: present
- type: str
- node:
- description:
- - Node on which the device is located.
- type: str
- required: true
- clear_logs:
- description:
- - Clear logs on the device after update. Default value is true
- type: bool
- default: true
- package:
- description:
- - Name of the package file containing the firmware to be installed. Not required when -baseline is true.
- type: str
- shelf_module_fw:
- description:
- - Shelf module firmware to be updated to.
- type: str
- disk_fw:
- description:
- - disk firmware to be updated to.
- type: str
- update_type:
- description:
- - Type of firmware update to be performed. Options include serial_full, serial_differential, network_full.
- type: str
- install_baseline_image:
- description:
- - Install the version packaged with ONTAP if this parameter is set to true. Otherwise, package must be used to specify the package to install.
- type: bool
- default: false
- firmware_type:
- description:
- - Type of firmware to be upgraded. Options include shelf, ACP, service-processor, and disk.
- - For shelf firmware upgrade the operation is asynchronous, and therefore returns no errors that might occur during the download process.
- - Shelf firmware upgrade is idempotent if shelf_module_fw is provided .
- - disk firmware upgrade is idempotent if disk_fw is provided .
- - With check mode, SP, ACP, disk, and shelf firmware upgrade is not idempotent.
- - This operation will only update firmware on shelves/disk that do not have the latest firmware-revision.
- choices: ['service-processor', 'shelf', 'acp', 'disk']
- type: str
-short_description: NetApp ONTAP firmware upgrade for SP, shelf, ACP, and disk.
-version_added: "2.9"
-'''
-
-EXAMPLES = """
-
- - name: SP firmware upgrade
- na_ontap_firmware_upgrade:
- state: present
- node: vsim1
- package: "{{ file name }}"
- clear_logs: True
- install_baseline_image: False
- update_type: serial_full
- firmware_type: service-processor
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: ACP firmware upgrade
- na_ontap_firmware_upgrade:
- state: present
- node: vsim1
- firmware_type: acp
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: shelf firmware upgrade
- na_ontap_firmware_upgrade:
- state: present
- firmware_type: shelf
- shelf_module_fw: 1221
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: disk firmware upgrade
- na_ontap_firmware_upgrade:
- state: present
- firmware_type: disk
- disk_fw: NA02
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-import time
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPFirmwareUpgrade(object):
- """
- Class with ONTAP firmware upgrade methods
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', default='present'),
- node=dict(required=False, type='str'),
- firmware_type=dict(required=True, type='str', choices=['service-processor', 'shelf', 'acp', 'disk']),
- clear_logs=dict(required=False, type='bool', default=True),
- package=dict(required=False, type='str'),
- install_baseline_image=dict(required=False, type='bool', default=False),
- update_type=dict(required=False, type='str'),
- shelf_module_fw=dict(required=False, type='str'),
- disk_fw=dict(required=False, type='str')
-
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('firmware_type', 'acp', ['node']),
- ('firmware_type', 'disk', ['node']),
- ('firmware_type', 'service-processor', ['node', 'update_type']),
- ],
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- if self.parameters.get('firmware_type') == 'service-processor':
- if self.parameters.get('install_baseline_image') and self.parameters.get('package') is not None:
- self.module.fail_json(msg='Do not specify both package and install_baseline_image: true')
- if not self.parameters.get('package') and self.parameters.get('install_baseline_image') == 'False':
- self.module.fail_json(msg='Specify at least one of package or install_baseline_image')
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def firmware_image_get_iter(self):
- """
- Compose NaElement object to query current firmware version
- :return: NaElement object for firmware_image_get_iter with query
- """
- firmware_image_get = netapp_utils.zapi.NaElement('service-processor-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- firmware_image_info = netapp_utils.zapi.NaElement('service-processor-info')
- firmware_image_info.add_new_child('node', self.parameters['node'])
- query.add_child_elem(firmware_image_info)
- firmware_image_get.add_child_elem(query)
- return firmware_image_get
-
- def firmware_image_get(self, node_name):
- """
- Get current firmware image info
- :return: True if query successful, else return None
- """
- firmware_image_get_iter = self.firmware_image_get_iter()
- try:
- result = self.server.invoke_successfully(firmware_image_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching firmware image details: %s: %s'
- % (self.parameters['node'], to_native(error)),
- exception=traceback.format_exc())
- # return firmware image details
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) > 0:
- sp_info = result.get_child_by_name('attributes-list').get_child_by_name('service-processor-info')
- firmware_version = sp_info.get_child_content('firmware-version')
- return firmware_version
- return None
-
- def acp_firmware_required_get(self):
- """
- where acp firmware upgrade is required
- :return: True is firmware upgrade is required else return None
- """
- acp_firmware_get_iter = netapp_utils.zapi.NaElement('storage-shelf-acp-module-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- acp_info = netapp_utils.zapi.NaElement('storage-shelf-acp-module')
- query.add_child_elem(acp_info)
- acp_firmware_get_iter.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(acp_firmware_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching acp firmware details details: %s'
- % (to_native(error)), exception=traceback.format_exc())
- if result.get_child_by_name('attributes-list').get_child_by_name('storage-shelf-acp-module'):
- acp_module_info = result.get_child_by_name('attributes-list').get_child_by_name(
- 'storage-shelf-acp-module')
- state = acp_module_info.get_child_content('state')
- if state == 'firmware_update_required':
- # acp firmware version upgrade required
- return True
- return False
-
- def sp_firmware_image_update_progress_get(self, node_name):
- """
- Get current firmware image update progress info
- :return: Dictionary of firmware image update progress if query successful, else return None
- """
- firmware_update_progress_get = netapp_utils.zapi.NaElement('service-processor-image-update-progress-get')
- firmware_update_progress_get.add_new_child('node', self.parameters['node'])
-
- firmware_update_progress_info = dict()
- try:
- result = self.server.invoke_successfully(firmware_update_progress_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching firmware image upgrade progress details: %s'
- % (to_native(error)), exception=traceback.format_exc())
- # return firmware image update progress details
- if result.get_child_by_name('attributes').get_child_by_name('service-processor-image-update-progress-info'):
- update_progress_info = result.get_child_by_name('attributes').get_child_by_name('service-processor-image-update-progress-info')
- firmware_update_progress_info['is-in-progress'] = update_progress_info.get_child_content('is-in-progress')
- firmware_update_progress_info['node'] = update_progress_info.get_child_content('node')
- return firmware_update_progress_info
-
- def shelf_firmware_info_get(self):
- """
- Get the current firmware of shelf module
- :return:dict with module id and firmware info
- """
- shelf_id_fw_info = dict()
- shelf_firmware_info_get = netapp_utils.zapi.NaElement('storage-shelf-info-get-iter')
- desired_attributes = netapp_utils.zapi.NaElement('desired-attributes')
- storage_shelf_info = netapp_utils.zapi.NaElement('storage-shelf-info')
- shelf_module = netapp_utils.zapi.NaElement('shelf-modules')
- shelf_module_info = netapp_utils.zapi.NaElement('storage-shelf-module-info')
- shelf_module.add_child_elem(shelf_module_info)
- storage_shelf_info.add_child_elem(shelf_module)
- desired_attributes.add_child_elem(storage_shelf_info)
- shelf_firmware_info_get.add_child_elem(desired_attributes)
-
- try:
- result = self.server.invoke_successfully(shelf_firmware_info_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching shelf module firmware details: %s'
- % (to_native(error)), exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) > 0:
- shelf_info = result.get_child_by_name('attributes-list').get_child_by_name('storage-shelf-info')
- if (shelf_info.get_child_by_name('shelf-modules') and
- shelf_info.get_child_by_name('shelf-modules').get_child_by_name('storage-shelf-module-info')):
- shelves = shelf_info['shelf-modules'].get_children()
- for shelf in shelves:
- shelf_id_fw_info[shelf.get_child_content('module-id')] = shelf.get_child_content('module-fw-revision')
- return shelf_id_fw_info
-
- def disk_firmware_info_get(self):
- """
- Get the current firmware of disks module
- :return:
- """
- disk_id_fw_info = dict()
- disk_firmware_info_get = netapp_utils.zapi.NaElement('storage-disk-get-iter')
- desired_attributes = netapp_utils.zapi.NaElement('desired-attributes')
- storage_disk_info = netapp_utils.zapi.NaElement('storage-disk-info')
- disk_inv = netapp_utils.zapi.NaElement('disk-inventory-info')
- storage_disk_info.add_child_elem(disk_inv)
- desired_attributes.add_child_elem(storage_disk_info)
- disk_firmware_info_get.add_child_elem(desired_attributes)
- try:
- result = self.server.invoke_successfully(disk_firmware_info_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching disk module firmware details: %s'
- % (to_native(error)), exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) > 0:
- disk_info = result.get_child_by_name('attributes-list')
- disks = disk_info.get_children()
- for disk in disks:
- disk_id_fw_info[disk.get_child_content('disk-uid')] = disk.get_child_by_name('disk-inventory-info').get_child_content('firmware-revision')
- return disk_id_fw_info
-
- def disk_firmware_required_get(self):
- """
- Check weather disk firmware upgrade is required or not
- :return: True if the firmware upgrade is required
- """
- disk_firmware_info = self.disk_firmware_info_get()
- for disk in disk_firmware_info:
- if (disk_firmware_info[disk]) != self.parameters['disk_fw']:
- return True
- return False
-
- def shelf_firmware_required_get(self):
- """
- Check weather shelf firmware upgrade is required or not
- :return: True if the firmware upgrade is required
- """
- shelf_firmware_info = self.shelf_firmware_info_get()
- for module in shelf_firmware_info:
- if (shelf_firmware_info[module]) != self.parameters['shelf_module_fw']:
- return True
- return False
-
- def sp_firmware_image_update(self):
- """
- Update current firmware image
- """
- firmware_update_info = netapp_utils.zapi.NaElement('service-processor-image-update')
- if self.parameters.get('package') is not None:
- firmware_update_info.add_new_child('package', self.parameters['package'])
- if self.parameters.get('clear_logs') is not None:
- firmware_update_info.add_new_child('clear-logs', str(self.parameters['clear_logs']))
- if self.parameters.get('install_baseline_image') is not None:
- firmware_update_info.add_new_child('install-baseline-image', str(self.parameters['install_baseline_image']))
- firmware_update_info.add_new_child('node', self.parameters['node'])
- firmware_update_info.add_new_child('update-type', self.parameters['update_type'])
-
- try:
- self.server.invoke_successfully(firmware_update_info, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- # Current firmware version matches the version to be installed
- if to_native(error.code) == '13001' and (error.message.startswith('Service Processor update skipped')):
- return False
- self.module.fail_json(msg='Error updating firmware image for %s: %s'
- % (self.parameters['node'], to_native(error)),
- exception=traceback.format_exc())
- return True
-
- def shelf_firmware_upgrade(self):
- """
- Upgrade shelf firmware image
- """
- shelf_firmware_update_info = netapp_utils.zapi.NaElement('storage-shelf-firmware-update')
- try:
- self.server.invoke_successfully(shelf_firmware_update_info, enable_tunneling=True)
- return True
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error updating shelf firmware image : %s'
- % (to_native(error)), exception=traceback.format_exc())
-
- def acp_firmware_upgrade(self):
-
- """
- Upgrade shelf firmware image
- """
- acp_firmware_update_info = netapp_utils.zapi.NaElement('storage-shelf-acp-firmware-update')
- acp_firmware_update_info.add_new_child('node-name', self.parameters['node'])
- try:
- self.server.invoke_successfully(acp_firmware_update_info, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error updating acp firmware image : %s'
- % (to_native(error)), exception=traceback.format_exc())
-
- def disk_firmware_upgrade(self):
-
- """
- Upgrade disk firmware
- """
- disk_firmware_update_info = netapp_utils.zapi.NaElement('disk-update-disk-fw')
- disk_firmware_update_info.add_new_child('node-name', self.parameters['node'])
- try:
- self.server.invoke_successfully(disk_firmware_update_info, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error updating disk firmware image : %s'
- % (to_native(error)), exception=traceback.format_exc())
- return True
-
- def autosupport_log(self):
- """
- Autosupport log for software_update
- :return:
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_firmware_upgrade", cserver)
-
- def apply(self):
- """
- Apply action to upgrade firmware
- """
- changed = False
- self.autosupport_log()
- firmware_update_progress = dict()
- if self.parameters.get('firmware_type') == 'service-processor':
- # service-processor firmware upgrade
- current = self.firmware_image_get(self.parameters['node'])
-
- if self.parameters.get('state') == 'present' and current:
- if not self.module.check_mode:
- if self.sp_firmware_image_update():
- changed = True
- firmware_update_progress = self.sp_firmware_image_update_progress_get(self.parameters['node'])
- while firmware_update_progress.get('is-in-progress') == 'true':
- time.sleep(25)
- firmware_update_progress = self.sp_firmware_image_update_progress_get(self.parameters['node'])
- else:
- # we don't know until we try the upgrade
- changed = True
-
- elif self.parameters.get('firmware_type') == 'shelf':
- # shelf firmware upgrade
- if self.parameters.get('shelf_module_fw'):
- if self.shelf_firmware_required_get():
- if not self.module.check_mode:
- changed = self.shelf_firmware_upgrade()
- else:
- changed = True
- else:
- if not self.module.check_mode:
- changed = self.shelf_firmware_upgrade()
- else:
- # we don't know until we try the upgrade -- assuming the worst
- changed = True
- elif self.parameters.get('firmware_type') == 'acp':
- # acp firmware upgrade
- if self.acp_firmware_required_get():
- if not self.module.check_mode:
- self.acp_firmware_upgrade()
- changed = True
- elif self.parameters.get('firmware_type') == 'disk':
- # Disk firmware upgrade
- if self.parameters.get('disk_fw'):
- if self.disk_firmware_required_get():
- if not self.module.check_mode:
- changed = self.disk_firmware_upgrade()
- else:
- changed = True
- else:
- if not self.module.check_mode:
- changed = self.disk_firmware_upgrade()
- else:
- # we don't know until we try the upgrade -- assuming the worst
- changed = True
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- """Execute action"""
- community_obj = NetAppONTAPFirmwareUpgrade()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_flexcache.py b/lib/ansible/modules/storage/netapp/na_ontap_flexcache.py
deleted file mode 100644
index 3b72e7d4d2..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_flexcache.py
+++ /dev/null
@@ -1,474 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-short_description: NetApp ONTAP FlexCache - create/delete relationship
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Create/Delete FlexCache volume relationships
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_flexcache
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified relationship should exist or not.
- default: present
- origin_volume:
- description:
- - Name of the origin volume for the FlexCache.
- - Required for creation.
- origin_vserver:
- description:
- - Name of the origin vserver for the FlexCache.
- - Required for creation.
- origin_cluster:
- description:
- - Name of the origin cluster for the FlexCache.
- - Defaults to cluster associated with target vserver if absent.
- - Not used for creation.
- volume:
- description:
- - Name of the target volume for the FlexCache.
- required: true
- junction_path:
- description:
- - Junction path of the cache volume.
- auto_provision_as:
- description:
- - Use this parameter to automatically select existing aggregates for volume provisioning.Eg flexgroup
- - Note that the fastest aggregate type with at least one aggregate on each node of the cluster will be selected.
- size:
- description:
- - Size of cache volume.
- size_unit:
- description:
- - The unit used to interpret the size parameter.
- choices: ['bytes', 'b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb']
- default: gb
- vserver:
- description:
- - Name of the target vserver for the FlexCache.
- - Note that hostname, username, password are intended for the target vserver.
- required: true
- aggr_list:
- description:
- - List of aggregates to host target FlexCache volume.
- aggr_list_multiplier:
- description:
- - Aggregate list repeat count.
- force_unmount:
- description:
- - Unmount FlexCache volume. Delete the junction path at which the volume is mounted before deleting the FlexCache relationship.
- type: bool
- default: false
- force_offline:
- description:
- - Offline FlexCache volume before deleting the FlexCache relationship.
- - The volume will be destroyed and data can be lost.
- type: bool
- default: false
- time_out:
- description:
- - time to wait for flexcache creation or deletion in seconds
- - if 0, the request is asynchronous
- - default is set to 3 minutes
- default: 180
-version_added: "2.8"
-'''
-
-EXAMPLES = """
-
- - name: Create FlexCache
- na_ontap_FlexCache:
- state: present
- origin_volume: test_src
- volume: test_dest
- origin_vserver: ansible_src
- vserver: ansible_dest
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete FlexCache
- na_ontap_FlexCache:
- state: absent
- volume: test_dest
- vserver: ansible_dest
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-"""
-
-RETURN = """
-"""
-
-import time
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPFlexCache(object):
- """
- Class with FlexCache methods
- """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'],
- default='present'),
- origin_volume=dict(required=False, type='str'),
- origin_vserver=dict(required=False, type='str'),
- origin_cluster=dict(required=False, type='str'),
- auto_provision_as=dict(required=False, type='str'),
- volume=dict(required=True, type='str'),
- junction_path=dict(required=False, type='str'),
- size=dict(required=False, type='int'),
- size_unit=dict(default='gb',
- choices=['bytes', 'b', 'kb', 'mb', 'gb', 'tb',
- 'pb', 'eb', 'zb', 'yb'], type='str'),
- vserver=dict(required=True, type='str'),
- aggr_list=dict(required=False, type='list'),
- aggr_list_multiplier=dict(required=False, type='int'),
- force_offline=dict(required=False, type='bool', default=False),
- force_unmount=dict(required=False, type='bool', default=False),
- time_out=dict(required=False, type='int', default=180),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- mutually_exclusive=[
- ('aggr_list', 'auto_provision_as'),
- ],
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- if self.parameters.get('size'):
- self.parameters['size'] = self.parameters['size'] * \
- netapp_utils.POW2_BYTE_MAP[self.parameters['size_unit']]
- # setup later if required
- self.origin_server = None
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def add_parameter_to_dict(self, adict, name, key=None, tostr=False):
- ''' add defined parameter (not None) to adict using key '''
- if key is None:
- key = name
- if self.parameters.get(name) is not None:
- if tostr:
- adict[key] = str(self.parameters.get(name))
- else:
- adict[key] = self.parameters.get(name)
-
- def get_job(self, jobid, server):
- """
- Get job details by id
- """
- job_get = netapp_utils.zapi.NaElement('job-get')
- job_get.add_new_child('job-id', jobid)
- try:
- result = server.invoke_successfully(job_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- if to_native(error.code) == "15661":
- # Not found
- return None
- self.module.fail_json(msg='Error fetching job info: %s' % to_native(error),
- exception=traceback.format_exc())
- results = dict()
- job_info = result.get_child_by_name('attributes').get_child_by_name('job-info')
- results = {
- 'job-progress': job_info['job-progress'],
- 'job-state': job_info['job-state']
- }
- if job_info.get_child_by_name('job-completion') is not None:
- results['job-completion'] = job_info['job-completion']
- else:
- results['job-completion'] = None
- return results
-
- def check_job_status(self, jobid):
- """
- Loop until job is complete
- """
- server = self.server
- sleep_time = 5
- time_out = self.parameters['time_out']
- while time_out > 0:
- results = self.get_job(jobid, server)
- # If running as cluster admin, the job is owned by cluster vserver
- # rather than the target vserver.
- if results is None and server == self.server:
- results = netapp_utils.get_cserver(self.server)
- server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- continue
- if results is None:
- error = 'cannot locate job with id: %d' % jobid
- break
- if results['job-state'] in ('queued', 'running'):
- time.sleep(sleep_time)
- time_out -= sleep_time
- continue
- if results['job-state'] in ('success', 'failure'):
- break
- else:
- self.module.fail_json(msg='Unexpected job status in: %s' % repr(results))
-
- if results is not None:
- if results['job-state'] == 'success':
- error = None
- elif results['job-state'] in ('queued', 'running'):
- error = 'job completion exceeded expected timer of: %s seconds' % \
- self.parameters['time_out']
- else:
- if results['job-completion'] is not None:
- error = results['job-completion']
- else:
- error = results['job-progress']
- return error
-
- def flexcache_get_iter(self):
- """
- Compose NaElement object to query current FlexCache relation
- """
- options = {'volume': self.parameters['volume']}
- self.add_parameter_to_dict(options, 'origin_volume', 'origin-volume')
- self.add_parameter_to_dict(options, 'origin_vserver', 'origin-vserver')
- self.add_parameter_to_dict(options, 'origin_cluster', 'origin-cluster')
- flexcache_info = netapp_utils.zapi.NaElement.create_node_with_children(
- 'flexcache-info', **options)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(flexcache_info)
- flexcache_get_iter = netapp_utils.zapi.NaElement('flexcache-get-iter')
- flexcache_get_iter.add_child_elem(query)
- return flexcache_get_iter
-
- def flexcache_get(self):
- """
- Get current FlexCache relations
- :return: Dictionary of current FlexCache details if query successful, else None
- """
- flexcache_get_iter = self.flexcache_get_iter()
- flex_info = dict()
- try:
- result = self.server.invoke_successfully(flexcache_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching FlexCache info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
- flexcache_info = result.get_child_by_name('attributes-list') \
- .get_child_by_name('flexcache-info')
- flex_info['origin_cluster'] = flexcache_info.get_child_content('origin-cluster')
- flex_info['origin_volume'] = flexcache_info.get_child_content('origin-volume')
- flex_info['origin_vserver'] = flexcache_info.get_child_content('origin-vserver')
- flex_info['size'] = flexcache_info.get_child_content('size')
- flex_info['volume'] = flexcache_info.get_child_content('volume')
- flex_info['vserver'] = flexcache_info.get_child_content('vserver')
- flex_info['auto_provision_as'] = flexcache_info.get_child_content('auto-provision-as')
-
- return flex_info
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) > 1:
- msg = 'Multiple records found for %s:' % self.parameters['volume']
- self.module.fail_json(msg='Error fetching FlexCache info: %s' % msg)
- return None
-
- def flexcache_create_async(self):
- """
- Create a FlexCache relationship
- """
- options = {'origin-volume': self.parameters['origin_volume'],
- 'origin-vserver': self.parameters['origin_vserver'],
- 'volume': self.parameters['volume']}
- self.add_parameter_to_dict(options, 'junction_path', 'junction-path')
- self.add_parameter_to_dict(options, 'auto_provision_as', 'auto-provision-as')
- self.add_parameter_to_dict(options, 'size', 'size', tostr=True)
- if self.parameters.get('aggr_list'):
- if self.parameters.get('aggr_list_multiplier'):
- self.tobytes_aggr_list_multiplier = bytes(self.parameters['aggr_list_multiplier'])
- self.add_parameter_to_dict(options, 'tobytes_aggr_list_multiplier', 'aggr-list-multiplier')
- flexcache_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'flexcache-create-async', **options)
- if self.parameters.get('aggr_list'):
- aggregates = netapp_utils.zapi.NaElement('aggr-list')
- for aggregate in self.parameters['aggr_list']:
- aggregates.add_new_child('aggr-name', aggregate)
- flexcache_create.add_child_elem(aggregates)
- try:
- result = self.server.invoke_successfully(flexcache_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating FlexCache %s' % to_native(error),
- exception=traceback.format_exc())
- results = dict()
- for key in ('result-status', 'result-jobid'):
- if result.get_child_by_name(key):
- results[key] = result[key]
- return results
-
- def flexcache_create(self):
- """
- Create a FlexCache relationship
- Check job status
- """
- results = self.flexcache_create_async()
- status = results.get('result-status')
- if status == 'in_progress' and 'result-jobid' in results:
- if self.parameters['time_out'] == 0:
- # asynchronous call, assuming success!
- return
- error = self.check_job_status(results['result-jobid'])
- if error is None:
- return
- else:
- self.module.fail_json(msg='Error when creating flexcache: %s' % error)
- self.module.fail_json(msg='Unexpected error when creating flexcache: results is: %s' % repr(results))
-
- def flexcache_delete_async(self):
- """
- Delete FlexCache relationship at destination cluster
- """
- options = {'volume': self.parameters['volume']}
- flexcache_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'flexcache-destroy-async', **options)
- try:
- result = self.server.invoke_successfully(flexcache_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting FlexCache : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
- results = dict()
- for key in ('result-status', 'result-jobid'):
- if result.get_child_by_name(key):
- results[key] = result[key]
- return results
-
- def volume_offline(self):
- """
- Offline FlexCache volume at destination cluster
- """
- options = {'name': self.parameters['volume']}
- xml = netapp_utils.zapi.NaElement.create_node_with_children(
- 'volume-offline', **options)
- try:
- self.server.invoke_successfully(xml, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error offlining FlexCache volume: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def volume_unmount(self):
- """
- Unmount FlexCache volume at destination cluster
- """
- options = {'volume-name': self.parameters['volume']}
- xml = netapp_utils.zapi.NaElement.create_node_with_children(
- 'volume-unmount', **options)
- try:
- self.server.invoke_successfully(xml, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error unmounting FlexCache volume: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def flexcache_delete_async(self):
- """
- Delete FlexCache relationship at destination cluster
- """
- options = {'volume': self.parameters['volume']}
- flexcache_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'flexcache-destroy-async', **options)
- try:
- result = self.server.invoke_successfully(flexcache_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting FlexCache : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
- results = dict()
- for key in ('result-status', 'result-jobid'):
- if result.get_child_by_name(key):
- results[key] = result[key]
- return results
-
- def flexcache_delete(self):
- """
- Delete FlexCache relationship at destination cluster
- Check job status
- """
- if self.parameters['force_unmount']:
- self.volume_unmount()
- if self.parameters['force_offline']:
- self.volume_offline()
- results = self.flexcache_delete_async()
- status = results.get('result-status')
- if status == 'in_progress' and 'result-jobid' in results:
- if self.parameters['time_out'] == 0:
- # asynchronous call, assuming success!
- return
- error = self.check_job_status(results['result-jobid'])
- if error is None:
- return
- else:
- self.module.fail_json(msg='Error when deleting flexcache: %s' % error)
- self.module.fail_json(msg='Unexpected error when deleting flexcache: results is: %s' % repr(results))
-
- def check_parameters(self):
- """
- Validate parameters and fail if one or more required params are missing
- """
- missings = list()
- expected = ('origin_volume', 'origin_vserver')
- if self.parameters['state'] == 'present':
- for param in expected:
- if not self.parameters.get(param):
- missings.append(param)
- if missings:
- plural = 's' if len(missings) > 1 else ''
- msg = 'Missing parameter%s: %s' % (plural, ', '.join(missings))
- self.module.fail_json(msg=msg)
-
- def apply(self):
- """
- Apply action to FlexCache
- """
- netapp_utils.ems_log_event("na_ontap_flexcache", self.server)
- current = self.flexcache_get()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action == 'create':
- self.check_parameters()
- self.flexcache_create()
- elif cd_action == 'delete':
- self.flexcache_delete()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """Execute action"""
- community_obj = NetAppONTAPFlexCache()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_igroup.py b/lib/ansible/modules/storage/netapp/na_ontap_igroup.py
deleted file mode 100644
index 57e808d687..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_igroup.py
+++ /dev/null
@@ -1,346 +0,0 @@
-#!/usr/bin/python
-''' this is igroup module
-
- (c) 2018-2019, NetApp, Inc
- # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-'''
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'
-}
-
-DOCUMENTATION = '''
-
-module: na_ontap_igroup
-short_description: NetApp ONTAP iSCSI or FC igroup configuration
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - Create/Delete/Rename Igroups and Modify initiators belonging to an igroup
-
-options:
- state:
- description:
- - Whether the specified Igroup should exist or not.
- choices: ['present', 'absent']
- default: present
-
- name:
- description:
- - The name of the igroup to manage.
- required: true
-
- initiator_group_type:
- description:
- - Type of the initiator group.
- - Required when C(state=present).
- choices: ['fcp', 'iscsi', 'mixed']
-
- from_name:
- description:
- - Name of igroup to rename to name.
- version_added: '2.7'
-
- ostype:
- description:
- - OS type of the initiators within the group.
-
- initiators:
- description:
- - List of initiators to be mapped to the igroup.
- - WWPN, WWPN Alias, or iSCSI name of Initiator to add or remove.
- - For a modify operation, this list replaces the existing initiators
- - This module does not add or remove specific initiator(s) in an igroup
- aliases:
- - initiator
-
- bind_portset:
- description:
- - Name of a current portset to bind to the newly created igroup.
-
- force_remove_initiator:
- description:
- - Forcibly remove the initiator even if there are existing LUNs mapped to this initiator group.
- type: bool
-
- vserver:
- description:
- - The name of the vserver to use.
- required: true
-
-'''
-
-EXAMPLES = '''
- - name: Create iSCSI Igroup
- na_ontap_igroup:
- state: present
- name: ansibleIgroup3
- initiator_group_type: iscsi
- ostype: linux
- initiators: iqn.1994-05.com.redhat:scspa0395855001.rtp.openenglab.netapp.com,abc.com:redhat.com
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Create FC Igroup
- na_ontap_igroup:
- state: present
- name: ansibleIgroup4
- initiator_group_type: fcp
- ostype: linux
- initiators: 20:00:00:50:56:9f:19:82
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: rename Igroup
- na_ontap_igroup:
- state: present
- from_name: ansibleIgroup3
- name: testexamplenewname
- initiator_group_type: iscsi
- ostype: linux
- initiators: iqn.1994-05.com.redhat:scspa0395855001.rtp.openenglab.netapp.com
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Modify Igroup Initiators (replaces existing initiators)
- na_ontap_igroup:
- state: present
- name: ansibleIgroup3
- initiator_group_type: iscsi
- ostype: linux
- initiator: iqn.1994-05.com.redhat:scspa0395855001.rtp.openenglab.netapp.com
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete Igroup
- na_ontap_igroup:
- state: absent
- name: ansibleIgroup3
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-'''
-
-RETURN = '''
-'''
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapIgroup(object):
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- from_name=dict(required=False, type='str', default=None),
- ostype=dict(required=False, type='str'),
- initiator_group_type=dict(required=False, type='str',
- choices=['fcp', 'iscsi', 'mixed']),
- initiators=dict(required=False, type='list', aliases=['initiator']),
- vserver=dict(required=True, type='str'),
- force_remove_initiator=dict(required=False, type='bool', default=False),
- bind_portset=dict(required=False, type='str')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_igroup(self, name):
- """
- Return details about the igroup
- :param:
- name : Name of the igroup
-
- :return: Details about the igroup. None if not found.
- :rtype: dict
- """
- igroup_info = netapp_utils.zapi.NaElement('igroup-get-iter')
- attributes = dict(query={'initiator-group-info': {'initiator-group-name': name,
- 'vserver': self.parameters['vserver']}})
- igroup_info.translate_struct(attributes)
- result, current = None, None
-
- try:
- result = self.server.invoke_successfully(igroup_info, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching igroup info %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- igroup = result.get_child_by_name('attributes-list').get_child_by_name('initiator-group-info')
- initiators = []
- if igroup.get_child_by_name('initiators'):
- current_initiators = igroup['initiators'].get_children()
- for initiator in current_initiators:
- initiators.append(initiator['initiator-name'])
- current = {
- 'initiators': initiators
- }
-
- return current
-
- def add_initiators(self):
- """
- Add the list of initiators to igroup
- :return: None
- """
- # don't add if initiators is empty string
- if self.parameters.get('initiators') == [''] or self.parameters.get('initiators') is None:
- return
- for initiator in self.parameters['initiators']:
- self.modify_initiator(initiator, 'igroup-add')
-
- def remove_initiators(self, initiators):
- """
- Removes all existing initiators from igroup
- :return: None
- """
- for initiator in initiators:
- self.modify_initiator(initiator, 'igroup-remove')
-
- def modify_initiator(self, initiator, zapi):
- """
- Add or remove an initiator to/from an igroup
- """
- initiator.strip() # remove leading spaces if any (eg: if user types a space after comma in initiators list)
- options = {'initiator-group-name': self.parameters['name'],
- 'initiator': initiator}
-
- igroup_modify = netapp_utils.zapi.NaElement.create_node_with_children(zapi, **options)
-
- try:
- self.server.invoke_successfully(igroup_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying igroup initiator %s: %s' % (self.parameters['name'],
- to_native(error)),
- exception=traceback.format_exc())
-
- def create_igroup(self):
- """
- Create the igroup.
- """
- options = {'initiator-group-name': self.parameters['name']}
- if self.parameters.get('ostype') is not None:
- options['os-type'] = self.parameters['ostype']
- if self.parameters.get('initiator_group_type') is not None:
- options['initiator-group-type'] = self.parameters['initiator_group_type']
- if self.parameters.get('bind_portset') is not None:
- options['bind-portset'] = self.parameters['bind_portset']
-
- igroup_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'igroup-create', **options)
-
- try:
- self.server.invoke_successfully(igroup_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error provisioning igroup %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- self.add_initiators()
-
- def delete_igroup(self):
- """
- Delete the igroup.
- """
- igroup_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'igroup-destroy', **{'initiator-group-name': self.parameters['name'],
- 'force': 'true' if self.parameters['force_remove_initiator'] else 'false'})
-
- try:
- self.server.invoke_successfully(igroup_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting igroup %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def rename_igroup(self):
- """
- Rename the igroup.
- """
- igroup_rename = netapp_utils.zapi.NaElement.create_node_with_children(
- 'igroup-rename', **{'initiator-group-name': self.parameters['from_name'],
- 'initiator-group-new-name': str(self.parameters['name'])})
- try:
- self.server.invoke_successfully(igroup_rename,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error renaming igroup %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- netapp_utils.ems_log_event("na_ontap_igroup", self.server)
-
- def apply(self):
- self.autosupport_log()
- current = self.get_igroup(self.parameters['name'])
- # rename and create are mutually exclusive
- rename, cd_action, modify = None, None, None
- if self.parameters.get('from_name'):
- rename = self.na_helper.is_rename_action(self.get_igroup(self.parameters['from_name']), current)
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action is None and self.parameters['state'] == 'present':
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_igroup()
- elif cd_action == 'create':
- self.create_igroup()
- elif cd_action == 'delete':
- self.delete_igroup()
- if modify:
- self.remove_initiators(current['initiators'])
- self.add_initiators()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- obj = NetAppOntapIgroup()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_igroup_initiator.py b/lib/ansible/modules/storage/netapp/na_ontap_igroup_initiator.py
deleted file mode 100644
index 1f784767e7..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_igroup_initiator.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/python
-''' This is an Ansible module for ONTAP, to manage initiators in an Igroup
-
- (c) 2019, NetApp, Inc
- # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-'''
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'
-}
-
-DOCUMENTATION = '''
-
-module: na_ontap_igroup_initiator
-short_description: NetApp ONTAP igroup initiator configuration
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - Add/Remove initiators from an igroup
-
-options:
- state:
- description:
- - Whether the specified initiator should exist or not in an igroup.
- choices: ['present', 'absent']
- default: present
-
- names:
- description:
- - List of initiators to manage.
- required: true
- aliases:
- - name
-
- initiator_group:
- description:
- - Name of the initiator group to which the initiator belongs.
- required: true
-
- vserver:
- description:
- - The name of the vserver to use.
- required: true
-
-'''
-
-EXAMPLES = '''
- - name: Add initiators to an igroup
- na_ontap_igroup_initiator:
- names: abc.test:def.com,def.test:efg.com
- initiator_group: test_group
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Remove an initiator from an igroup
- na_ontap_igroup_initiator:
- state: absent
- names: abc.test:def.com
- initiator_group: test_group
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-'''
-
-RETURN = '''
-'''
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapIgroupInitiator(object):
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- names=dict(required=True, type='list', aliases=['name']),
- initiator_group=dict(required=True, type='str'),
- vserver=dict(required=True, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_initiators(self):
- """
- Get the existing list of initiators from an igroup
- :rtype: list() or None
- """
- igroup_info = netapp_utils.zapi.NaElement('igroup-get-iter')
- attributes = dict(query={'initiator-group-info': {'initiator-group-name': self.parameters['initiator_group'],
- 'vserver': self.parameters['vserver']}})
- igroup_info.translate_struct(attributes)
- result, current = None, []
-
- try:
- result = self.server.invoke_successfully(igroup_info, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching igroup info %s: %s' % (self.parameters['initiator_group'],
- to_native(error)),
- exception=traceback.format_exc())
-
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- igroup_info = result.get_child_by_name('attributes-list').get_child_by_name('initiator-group-info')
- if igroup_info.get_child_by_name('initiators') is not None:
- current = [initiator['initiator-name'] for initiator in igroup_info['initiators'].get_children()]
- return current
-
- def modify_initiator(self, initiator_name, zapi):
- """
- Add or remove an initiator to/from an igroup
- """
- options = {'initiator-group-name': self.parameters['initiator_group'],
- 'initiator': initiator_name}
- initiator_modify = netapp_utils.zapi.NaElement.create_node_with_children(zapi, **options)
-
- try:
- self.server.invoke_successfully(initiator_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying igroup initiator %s: %s' % (initiator_name,
- to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- netapp_utils.ems_log_event("na_ontap_igroup_initiator", self.server)
-
- def apply(self):
- self.autosupport_log()
- initiators = self.get_initiators()
- for initiator in self.parameters['names']:
- present = None
- if initiator in initiators:
- present = True
- cd_action = self.na_helper.get_cd_action(present, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.modify_initiator(initiator, 'igroup-add')
- elif cd_action == 'delete':
- self.modify_initiator(initiator, 'igroup-remove')
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- obj = NetAppOntapIgroupInitiator()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_info.py b/lib/ansible/modules/storage/netapp/na_ontap_info.py
deleted file mode 100644
index 6945f68d83..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_info.py
+++ /dev/null
@@ -1,619 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018 Piotr Olczak <piotr.olczak@redhat.com>
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_info
-author: Piotr Olczak (@dprts) <polczak@redhat.com>
-extends_documentation_fragment:
- - netapp.na_ontap
-short_description: NetApp information gatherer
-description:
- - This module allows you to gather various information about ONTAP configuration
-version_added: "2.9"
-requirements:
- - netapp_lib
-options:
- state:
- type: str
- description:
- - Returns "info"
- default: "info"
- choices: ['info']
- gather_subset:
- type: list
- description:
- - When supplied, this argument will restrict the information collected
- to a given subset. Possible values for this argument include
- "aggregate_info", "cluster_node_info", "igroup_info", "lun_info", "net_dns_info",
- "net_ifgrp_info",
- "net_interface_info", "net_port_info", "nvme_info", "nvme_interface_info",
- "nvme_namespace_info", "nvme_subsystem_info", "ontap_version",
- "qos_adaptive_policy_info", "qos_policy_info", "security_key_manager_key_info",
- "security_login_account_info", "storage_failover_info", "volume_info",
- "vserver_info", "vserver_login_banner_info", "vserver_motd_info", "vserver_nfs_info"
- Can specify a list of values to include a larger subset. Values can also be used
- with an initial C(M(!)) to specify that a specific subset should
- not be collected.
- - nvme is supported with ONTAP 9.4 onwards.
- - use "help" to get a list of supported information for your system.
- default: "all"
-'''
-
-EXAMPLES = '''
-- name: Get NetApp info (Password Authentication)
- na_ontap_info:
- state: info
- hostname: "na-vsim"
- username: "admin"
- password: "admins_password"
- register: ontap_info
-- debug:
- msg: "{{ ontap_info.ontap_info }}"
-
-- name: Limit Info Gathering to Aggregate Information
- na_ontap_info:
- state: info
- hostname: "na-vsim"
- username: "admin"
- password: "admins_password"
- gather_subset: "aggregate_info"
- register: ontap_info
-
-- name: Limit Info Gathering to Volume and Lun Information
- na_ontap_info:
- state: info
- hostname: "na-vsim"
- username: "admin"
- password: "admins_password"
- gather_subset:
- - volume_info
- - lun_info
- register: ontap_info
-
-- name: Gather all info except for volume and lun information
- na_ontap_info:
- state: info
- hostname: "na-vsim"
- username: "admin"
- password: "admins_password"
- gather_subset:
- - "!volume_info"
- - "!lun_info"
- register: ontap_info
-'''
-
-RETURN = '''
-ontap_info:
- description: Returns various information about NetApp cluster configuration
- returned: always
- type: dict
- sample: '{
- "ontap_info": {
- "aggregate_info": {...},
- "cluster_node_info": {...},
- "net_dns_info": {...},
- "net_ifgrp_info": {...},
- "net_interface_info": {...},
- "net_port_info": {...},
- "security_key_manager_key_info": {...},
- "security_login_account_info": {...},
- "volume_info": {...},
- "lun_info": {...},
- "storage_failover_info": {...},
- "vserver_login_banner_info": {...},
- "vserver_motd_info": {...},
- "vserver_info": {...},
- "vserver_nfs_info": {...},
- "ontap_version": {...},
- "igroup_info": {...},
- "qos_policy_info": {...},
- "qos_adaptive_policy_info": {...}
- }'
-'''
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-try:
- import xmltodict
- HAS_XMLTODICT = True
-except ImportError:
- HAS_XMLTODICT = False
-
-try:
- import json
- HAS_JSON = True
-except ImportError:
- HAS_JSON = False
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPGatherInfo(object):
- '''Class with gather info methods'''
-
- def __init__(self, module):
- self.module = module
- self.netapp_info = dict()
-
- # thanks to coreywan (https://github.com/ansible/ansible/pull/47016)
- # for starting this
- # min_version identifies the ontapi version which supports this ZAPI
- # use 0 if it is supported since 9.1
- self.info_subsets = {
- 'net_dns_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'net-dns-get-iter',
- 'attribute': 'net-dns-info',
- 'field': 'vserver-name',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'net_interface_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'net-interface-get-iter',
- 'attribute': 'net-interface-info',
- 'field': 'interface-name',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'net_port_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'net-port-get-iter',
- 'attribute': 'net-port-info',
- 'field': ('node', 'port'),
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'cluster_node_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'cluster-node-get-iter',
- 'attribute': 'cluster-node-info',
- 'field': 'node-name',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'security_login_account_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'security-login-get-iter',
- 'attribute': 'security-login-account-info',
- 'field': ('vserver', 'user-name', 'application', 'authentication-method'),
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'aggregate_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'aggr-get-iter',
- 'attribute': 'aggr-attributes',
- 'field': 'aggregate-name',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'volume_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'volume-get-iter',
- 'attribute': 'volume-attributes',
- 'field': ('name', 'owning-vserver-name'),
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'lun_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'lun-get-iter',
- 'attribute': 'lun-info',
- 'field': ('vserver', 'path'),
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'storage_failover_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'cf-get-iter',
- 'attribute': 'storage-failover-info',
- 'field': 'node',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'vserver_motd_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'vserver-motd-get-iter',
- 'attribute': 'vserver-motd-info',
- 'field': 'vserver',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'vserver_login_banner_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'vserver-login-banner-get-iter',
- 'attribute': 'vserver-login-banner-info',
- 'field': 'vserver',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'security_key_manager_key_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'security-key-manager-key-get-iter',
- 'attribute': 'security-key-manager-key-info',
- 'field': ('node', 'key-id'),
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'vserver_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'vserver-get-iter',
- 'attribute': 'vserver-info',
- 'field': 'vserver-name',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'vserver_nfs_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'nfs-service-get-iter',
- 'attribute': 'nfs-info',
- 'field': 'vserver',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'net_ifgrp_info': {
- 'method': self.get_ifgrp_info,
- 'kwargs': {},
- 'min_version': '0',
- },
- 'ontap_version': {
- 'method': self.ontapi,
- 'kwargs': {},
- 'min_version': '0',
- },
- 'system_node_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'system-node-get-iter',
- 'attribute': 'node-details-info',
- 'field': 'node',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'igroup_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'igroup-get-iter',
- 'attribute': 'initiator-group-info',
- 'field': ('vserver', 'initiator-group-name'),
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- 'qos_policy_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'qos-policy-group-get-iter',
- 'attribute': 'qos-policy-group-info',
- 'field': 'policy-group',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '0',
- },
- # supported in ONTAP 9.3 and onwards
- 'qos_adaptive_policy_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'qos-adaptive-policy-group-get-iter',
- 'attribute': 'qos-adaptive-policy-group-info',
- 'field': 'policy-group',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '130',
- },
- # supported in ONTAP 9.4 and onwards
- 'nvme_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'nvme-get-iter',
- 'attribute': 'nvme-target-service-info',
- 'field': 'vserver',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '140',
- },
- 'nvme_interface_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'nvme-interface-get-iter',
- 'attribute': 'nvme-interface-info',
- 'field': 'vserver',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '140',
- },
- 'nvme_subsystem_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'nvme-subsystem-get-iter',
- 'attribute': 'nvme-subsystem-info',
- 'field': 'subsystem',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '140',
- },
- 'nvme_namespace_info': {
- 'method': self.get_generic_get_iter,
- 'kwargs': {
- 'call': 'nvme-namespace-get-iter',
- 'attribute': 'nvme-namespace-info',
- 'field': 'path',
- 'query': {'max-records': '1024'},
- },
- 'min_version': '140',
- },
- }
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def ontapi(self):
- '''Method to get ontapi version'''
-
- api = 'system-get-ontapi-version'
- api_call = netapp_utils.zapi.NaElement(api)
- try:
- results = self.server.invoke_successfully(api_call, enable_tunneling=False)
- ontapi_version = results.get_child_content('minor-version')
- return ontapi_version if ontapi_version is not None else '0'
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error calling API %s: %s" %
- (api, to_native(error)), exception=traceback.format_exc())
-
- def call_api(self, call, query=None):
- '''Main method to run an API call'''
-
- api_call = netapp_utils.zapi.NaElement(call)
- result = None
-
- if query:
- for key, val in query.items():
- # Can val be nested?
- api_call.add_new_child(key, val)
- try:
- result = self.server.invoke_successfully(api_call, enable_tunneling=False)
- return result
- except netapp_utils.zapi.NaApiError as error:
- if call in ['security-key-manager-key-get-iter']:
- return result
- else:
- self.module.fail_json(msg="Error calling API %s: %s"
- % (call, to_native(error)), exception=traceback.format_exc())
-
- def get_ifgrp_info(self):
- '''Method to get network port ifgroups info'''
-
- try:
- net_port_info = self.netapp_info['net_port_info']
- except KeyError:
- net_port_info_calls = self.info_subsets['net_port_info']
- net_port_info = net_port_info_calls['method'](**net_port_info_calls['kwargs'])
- interfaces = net_port_info.keys()
-
- ifgrps = []
- for ifn in interfaces:
- if net_port_info[ifn]['port_type'] == 'if_group':
- ifgrps.append(ifn)
-
- net_ifgrp_info = dict()
- for ifgrp in ifgrps:
- query = dict()
- query['node'], query['ifgrp-name'] = ifgrp.split(':')
-
- tmp = self.get_generic_get_iter('net-port-ifgrp-get', field=('node', 'ifgrp-name'),
- attribute='net-ifgrp-info', query=query)
- net_ifgrp_info = net_ifgrp_info.copy()
- net_ifgrp_info.update(tmp)
- return net_ifgrp_info
-
- def get_generic_get_iter(self, call, attribute=None, field=None, query=None):
- '''Method to run a generic get-iter call'''
-
- generic_call = self.call_api(call, query)
-
- if call == 'net-port-ifgrp-get':
- children = 'attributes'
- else:
- children = 'attributes-list'
-
- if generic_call is None:
- return None
-
- if field is None:
- out = []
- else:
- out = {}
-
- attributes_list = generic_call.get_child_by_name(children)
-
- if attributes_list is None:
- return None
-
- for child in attributes_list.get_children():
- dic = xmltodict.parse(child.to_string(), xml_attribs=False)
-
- if attribute is not None:
- dic = dic[attribute]
-
- if isinstance(field, str):
- unique_key = _finditem(dic, field)
- out = out.copy()
- out.update({unique_key: convert_keys(json.loads(json.dumps(dic)))})
- elif isinstance(field, tuple):
- unique_key = ':'.join([_finditem(dic, el) for el in field])
- out = out.copy()
- out.update({unique_key: convert_keys(json.loads(json.dumps(dic)))})
- else:
- out.append(convert_keys(json.loads(json.dumps(dic))))
-
- return out
-
- def get_all(self, gather_subset):
- '''Method to get all subsets'''
-
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_info", cserver)
-
- self.netapp_info['ontap_version'] = self.ontapi()
-
- run_subset = self.get_subset(gather_subset, self.netapp_info['ontap_version'])
- if 'help' in gather_subset:
- self.netapp_info['help'] = sorted(run_subset)
- else:
- for subset in run_subset:
- call = self.info_subsets[subset]
- self.netapp_info[subset] = call['method'](**call['kwargs'])
-
- return self.netapp_info
-
- def get_subset(self, gather_subset, version):
- '''Method to get a single subset'''
-
- runable_subsets = set()
- exclude_subsets = set()
- usable_subsets = [key for key in self.info_subsets.keys() if version >= self.info_subsets[key]['min_version']]
- if 'help' in gather_subset:
- return usable_subsets
- for subset in gather_subset:
- if subset == 'all':
- runable_subsets.update(usable_subsets)
- return runable_subsets
- if subset.startswith('!'):
- subset = subset[1:]
- if subset == 'all':
- return set()
- exclude = True
- else:
- exclude = False
-
- if subset not in usable_subsets:
- if subset not in self.info_subsets.keys():
- self.module.fail_json(msg='Bad subset: %s' % subset)
- self.module.fail_json(msg='Remote system at version %s does not support %s' %
- (version, subset))
-
- if exclude:
- exclude_subsets.add(subset)
- else:
- runable_subsets.add(subset)
-
- if not runable_subsets:
- runable_subsets.update(usable_subsets)
-
- runable_subsets.difference_update(exclude_subsets)
-
- return runable_subsets
-
-
-# https://stackoverflow.com/questions/14962485/finding-a-key-recursively-in-a-dictionary
-def __finditem(obj, key):
-
- if key in obj:
- return obj[key]
- for dummy, val in obj.items():
- if isinstance(val, dict):
- item = __finditem(val, key)
- if item is not None:
- return item
- return None
-
-
-def _finditem(obj, key):
-
- value = __finditem(obj, key)
- if value is not None:
- return value
- raise KeyError(key)
-
-
-def convert_keys(d_param):
- '''Method to convert hyphen to underscore'''
-
- out = {}
- if isinstance(d_param, dict):
- for key, val in d_param.items():
- val = convert_keys(val)
- out[key.replace('-', '_')] = val
- else:
- return d_param
- return out
-
-
-def main():
- '''Execute action'''
-
- argument_spec = netapp_utils.na_ontap_host_argument_spec()
- argument_spec.update(dict(
- state=dict(type='str', default='info', choices=['info']),
- gather_subset=dict(default=['all'], type='list'),
- ))
-
- module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
-
- if not HAS_XMLTODICT:
- module.fail_json(msg="xmltodict missing")
-
- if not HAS_JSON:
- module.fail_json(msg="json missing")
-
- state = module.params['state']
- gather_subset = module.params['gather_subset']
- if gather_subset is None:
- gather_subset = ['all']
- gf_obj = NetAppONTAPGatherInfo(module)
- gf_all = gf_obj.get_all(gather_subset)
- result = {'state': state, 'changed': False}
- module.exit_json(ontap_info=gf_all, **result)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_interface.py b/lib/ansible/modules/storage/netapp/na_ontap_interface.py
deleted file mode 100644
index 0b1abea6b3..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_interface.py
+++ /dev/null
@@ -1,449 +0,0 @@
-#!/usr/bin/python
-""" this is interface module
-
- (c) 2018-2019, NetApp, Inc
- # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'
-}
-
-DOCUMENTATION = '''
----
-
-module: na_ontap_interface
-short_description: NetApp ONTAP LIF configuration
-
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - Creating / deleting and modifying the LIF.
-
-options:
- state:
- description:
- - Whether the specified interface should exist or not.
- choices: ['present', 'absent']
- default: present
-
- interface_name:
- description:
- - Specifies the logical interface (LIF) name.
- required: true
-
- home_node:
- description:
- - Specifies the LIF's home node.
- - By default, the first node from the cluster is considered as home node
-
- home_port:
- description:
- - Specifies the LIF's home port.
- - Required when C(state=present)
-
- role:
- description:
- - Specifies the role of the LIF.
- - When setting role as "intercluster", setting protocol is not supported.
- - Required when C(state=present).
-
- address:
- description:
- - Specifies the LIF's IP address.
- - Required when C(state=present)
-
- netmask:
- description:
- - Specifies the LIF's netmask.
- - Required when C(state=present).
-
- vserver:
- description:
- - The name of the vserver to use.
- required: true
-
- firewall_policy:
- description:
- - Specifies the firewall policy for the LIF.
-
- failover_policy:
- choices: ['disabled', 'system-defined', 'local-only', 'sfo-partner-only', 'broadcast-domain-wide']
- description:
- - Specifies the failover policy for the LIF.
-
- subnet_name:
- description:
- - Subnet where the interface address is allocated from.
- If the option is not used, the IP address will need to be provided by
- the administrator during configuration.
- version_added: '2.8'
-
- admin_status:
- choices: ['up', 'down']
- description:
- - Specifies the administrative status of the LIF.
-
- is_auto_revert:
- description:
- If true, data LIF will revert to its home node under certain circumstances such as startup, and load balancing
- migration capability is disabled automatically
- type: bool
-
- force_subnet_association:
- description:
- Set this to true to acquire the address from the named subnet and assign the subnet to the LIF.
- type: bool
- version_added: '2.9'
-
- protocols:
- description:
- - Specifies the list of data protocols configured on the LIF. By default, the values in this element are nfs, cifs and fcache.
- - Other supported protocols are iscsi and fcp. A LIF can be configured to not support any data protocols by specifying 'none'.
- - Protocol values of none, iscsi, fc-nvme or fcp can't be combined with any other data protocol(s).
- - address, netmask and firewall_policy parameters are not supported for 'fc-nvme' option.
-
- dns_domain_name:
- description:
- - Specifies the unique, fully qualified domain name of the DNS zone of this LIF.
- type: str
- version_added: '2.9'
-
- listen_for_dns_query:
- description:
- - If True, this IP address will listen for DNS queries for the dnszone specified.
- type: bool
- version_added: '2.9'
-
- is_dns_update_enabled:
- description:
- - Specifies if DNS update is enabled for this LIF. Dynamic updates will be sent for this LIF if updates are enabled at Vserver level.
- type: bool
- version_added: '2.9'
-
-'''
-
-EXAMPLES = '''
- - name: Create interface
- na_ontap_interface:
- state: present
- interface_name: data2
- home_port: e0d
- home_node: laurentn-vsim1
- role: data
- protocols: nfs
- admin_status: up
- failover_policy: local-only
- firewall_policy: mgmt
- is_auto_revert: true
- address: 10.10.10.10
- netmask: 255.255.255.0
- force_subnet_association: false
- dns_domain_name: test.com
- listen_for_dns_query: true
- is_dns_update_enabled: true
- vserver: svm1
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete interface
- na_ontap_interface:
- state: absent
- interface_name: data2
- vserver: svm1
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-'''
-
-RETURN = """
-
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapInterface(object):
- ''' object to describe interface info '''
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- interface_name=dict(required=True, type='str'),
- home_node=dict(required=False, type='str', default=None),
- home_port=dict(required=False, type='str'),
- role=dict(required=False, type='str'),
- address=dict(required=False, type='str'),
- netmask=dict(required=False, type='str'),
- vserver=dict(required=True, type='str'),
- firewall_policy=dict(required=False, type='str', default=None),
- failover_policy=dict(required=False, type='str', default=None,
- choices=['disabled', 'system-defined',
- 'local-only', 'sfo-partner-only', 'broadcast-domain-wide']),
- admin_status=dict(required=False, choices=['up', 'down']),
- subnet_name=dict(required=False, type='str'),
- is_auto_revert=dict(required=False, type='bool', default=None),
- protocols=dict(required=False, type='list'),
- force_subnet_association=dict(required=False, type='bool', default=None),
- dns_domain_name=dict(required=False, type='str'),
- listen_for_dns_query=dict(required=False, type='bool'),
- is_dns_update_enabled=dict(required=False, type='bool')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- mutually_exclusive=[
- ['subnet_name', 'address'],
- ['subnet_name', 'netmask']
- ],
-
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def get_interface(self):
- """
- Return details about the interface
- :param:
- name : Name of the name of the interface
-
- :return: Details about the interface. None if not found.
- :rtype: dict
- """
- interface_info = netapp_utils.zapi.NaElement('net-interface-get-iter')
- interface_attributes = netapp_utils.zapi.NaElement('net-interface-info')
- interface_attributes.add_new_child('interface-name', self.parameters['interface_name'])
- interface_attributes.add_new_child('vserver', self.parameters['vserver'])
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(interface_attributes)
- interface_info.add_child_elem(query)
- result = self.server.invoke_successfully(interface_info, True)
- return_value = None
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) >= 1:
-
- interface_attributes = result.get_child_by_name('attributes-list').\
- get_child_by_name('net-interface-info')
- return_value = {
- 'interface_name': self.parameters['interface_name'],
- 'admin_status': interface_attributes['administrative-status'],
- 'home_port': interface_attributes['home-port'],
- 'home_node': interface_attributes['home-node'],
- 'failover_policy': interface_attributes['failover-policy'].replace('_', '-'),
- 'is_auto_revert': True if interface_attributes['is-auto-revert'] == 'true' else False,
- }
- if interface_attributes.get_child_by_name('address'):
- return_value['address'] = interface_attributes['address']
- if interface_attributes.get_child_by_name('netmask'):
- return_value['netmask'] = interface_attributes['netmask']
- if interface_attributes.get_child_by_name('firewall-policy'):
- return_value['firewall_policy'] = interface_attributes['firewall-policy']
- if interface_attributes.get_child_by_name('dns-domain-name') != 'none':
- return_value['dns_domain_name'] = interface_attributes['dns-domain-name']
- else:
- return_value['dns_domain_name'] = None
- if interface_attributes.get_child_by_name('listen-for-dns-query'):
- return_value['listen_for_dns_query'] = self.na_helper.get_value_for_bool(True, interface_attributes['listen-for-dns-query'])
- if interface_attributes.get_child_by_name('is-dns-update-enabled'):
- return_value['is_dns_update_enabled'] = self.na_helper.get_value_for_bool(True, interface_attributes['is-dns-update-enabled'])
- return return_value
-
- @staticmethod
- def set_options(options, parameters):
- """ set attributes for create or modify """
- if parameters.get('home_port') is not None:
- options['home-port'] = parameters['home_port']
- if parameters.get('subnet_name') is not None:
- options['subnet-name'] = parameters['subnet_name']
- if parameters.get('address') is not None:
- options['address'] = parameters['address']
- if parameters.get('netmask') is not None:
- options['netmask'] = parameters['netmask']
- if parameters.get('failover_policy') is not None:
- options['failover-policy'] = parameters['failover_policy']
- if parameters.get('firewall_policy') is not None:
- options['firewall-policy'] = parameters['firewall_policy']
- if parameters.get('is_auto_revert') is not None:
- options['is-auto-revert'] = 'true' if parameters['is_auto_revert'] is True else 'false'
- if parameters.get('admin_status') is not None:
- options['administrative-status'] = parameters['admin_status']
- if parameters.get('force_subnet_association') is not None:
- options['force-subnet-association'] = 'true' if parameters['force_subnet_association'] else 'false'
- if parameters.get('dns_domain_name') is not None:
- options['dns-domain-name'] = parameters['dns_domain_name']
- if parameters.get('listen_for_dns_query') is not None:
- options['listen-for-dns-query'] = str(parameters['listen_for_dns_query'])
- if parameters.get('is_dns_update_enabled') is not None:
- options['is-dns-update-enabled'] = str(parameters['is_dns_update_enabled'])
-
- def set_protocol_option(self, required_keys):
- """ set protocols for create """
- if self.parameters.get('protocols') is not None:
- data_protocols_obj = netapp_utils.zapi.NaElement('data-protocols')
- for protocol in self.parameters.get('protocols'):
- if protocol.lower() in ['fc-nvme', 'fcp']:
- if 'address' in required_keys:
- required_keys.remove('address')
- if 'home_port' in required_keys:
- required_keys.remove('home_port')
- if 'netmask' in required_keys:
- required_keys.remove('netmask')
- not_required_params = set(['address', 'netmask', 'firewall_policy'])
- if not not_required_params.isdisjoint(set(self.parameters.keys())):
- self.module.fail_json(msg='Error: Following parameters for creating interface are not supported'
- ' for data-protocol fc-nvme: %s' % ', '.join(not_required_params))
- data_protocols_obj.add_new_child('data-protocol', protocol)
- return data_protocols_obj
- return None
-
- def get_home_node_for_cluster(self):
- ''' get the first node name from this cluster '''
- get_node = netapp_utils.zapi.NaElement('cluster-node-get-iter')
- attributes = {
- 'query': {
- 'cluster-node-info': {}
- }
- }
- get_node.translate_struct(attributes)
- try:
- result = self.server.invoke_successfully(get_node, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as exc:
- self.module.fail_json(msg='Error fetching node for interface %s: %s' %
- (self.parameters['interface_name'], to_native(exc)),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- attributes = result.get_child_by_name('attributes-list')
- return attributes.get_child_by_name('cluster-node-info').get_child_content('node-name')
- return None
-
- def validate_create_parameters(self, keys):
- '''
- Validate if required parameters for create are present.
- Parameter requirement might vary based on given data-protocol.
- :return: None
- '''
- if self.parameters.get('home_node') is None:
- node = self.get_home_node_for_cluster()
- if node is not None:
- self.parameters['home_node'] = node
- # validate if mandatory parameters are present for create
- if not keys.issubset(set(self.parameters.keys())) and self.parameters.get('subnet_name') is None:
- self.module.fail_json(msg='Error: Missing one or more required parameters for creating interface: %s'
- % ', '.join(keys))
- # if role is intercluster, protocol cannot be specified
- if self.parameters['role'] == "intercluster" and self.parameters.get('protocols') is not None:
- self.module.fail_json(msg='Error: Protocol cannot be specified for intercluster role,'
- 'failed to create interface')
-
- def create_interface(self):
- ''' calling zapi to create interface '''
- required_keys = set(['role', 'home_port'])
- data_protocols_obj = None
- if self.parameters.get('subnet_name') is None:
- required_keys.add('address')
- required_keys.add('netmask')
- data_protocols_obj = self.set_protocol_option(required_keys)
- self.validate_create_parameters(required_keys)
-
- options = {'interface-name': self.parameters['interface_name'],
- 'role': self.parameters['role'],
- 'home-node': self.parameters.get('home_node'),
- 'vserver': self.parameters['vserver']}
- NetAppOntapInterface.set_options(options, self.parameters)
- interface_create = netapp_utils.zapi.NaElement.create_node_with_children('net-interface-create', **options)
- if data_protocols_obj is not None:
- interface_create.add_child_elem(data_protocols_obj)
- try:
- self.server.invoke_successfully(interface_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as exc:
- self.module.fail_json(msg='Error Creating interface %s: %s' %
- (self.parameters['interface_name'], to_native(exc)), exception=traceback.format_exc())
-
- def delete_interface(self, current_status):
- ''' calling zapi to delete interface '''
- if current_status == 'up':
- self.parameters['admin_status'] = 'down'
- self.modify_interface({'admin_status': 'down'})
-
- interface_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'net-interface-delete', **{'interface-name': self.parameters['interface_name'],
- 'vserver': self.parameters['vserver']})
- try:
- self.server.invoke_successfully(interface_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as exc:
- self.module.fail_json(msg='Error deleting interface %s: %s' % (self.parameters['interface_name'], to_native(exc)),
- exception=traceback.format_exc())
-
- def modify_interface(self, modify):
- """
- Modify the interface.
- """
- options = {'interface-name': self.parameters['interface_name'],
- 'vserver': self.parameters['vserver']
- }
- NetAppOntapInterface.set_options(options, modify)
- interface_modify = netapp_utils.zapi.NaElement.create_node_with_children('net-interface-modify', **options)
- try:
- self.server.invoke_successfully(interface_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as err:
- self.module.fail_json(msg='Error modifying interface %s: %s' % (self.parameters['interface_name'],
- to_native(err)), exception=traceback.format_exc())
-
- def autosupport_log(self):
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_interface", cserver)
-
- def apply(self):
- ''' calling all interface features '''
- self.autosupport_log()
- current = self.get_interface()
- # rename and create are mutually exclusive
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_interface()
- elif cd_action == 'delete':
- self.delete_interface(current['admin_status'])
- elif modify:
- self.modify_interface(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- interface = NetAppOntapInterface()
- interface.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_ipspace.py b/lib/ansible/modules/storage/netapp/na_ontap_ipspace.py
deleted file mode 100644
index 56f1e87692..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_ipspace.py
+++ /dev/null
@@ -1,258 +0,0 @@
-#!/usr/bin/python
-"""
-this is ipspace module
-
-# (c) 2018, NTT Europe Ltd.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'
-}
-
-DOCUMENTATION = '''
----
-module: na_ontap_ipspace
-
-short_description: NetApp ONTAP Manage an ipspace
-
-version_added: '2.9'
-
-author:
- - NTTE Storage Engineering (@vicmunoz) <cl.eng.sto@ntt.eu>
-
-description:
- - Manage an ipspace for an Ontap Cluster
-
-extends_documentation_fragment:
- - netapp.na_ontap
-
-options:
- state:
- description:
- - Whether the specified ipspace should exist or not
- choices: ['present', 'absent']
- default: present
- name:
- description:
- - The name of the ipspace to manage
- required: true
- from_name:
- description:
- - Name of the existing ipspace to be renamed to name
-'''
-
-EXAMPLES = """
- - name: Create ipspace
- na_ontap_ipspace:
- state: present
- name: ansibleIpspace
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete ipspace
- na_ontap_ipspace:
- state: absent
- name: ansibleIpspace
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Rename ipspace
- na_ontap_ipspace:
- state: present
- name: ansibleIpspace_newname
- from_name: ansibleIpspace
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapIpspace(object):
- '''Class with ipspace operations'''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(
- required=False, choices=['present', 'absent'],
- default='present'),
- name=dict(required=True, type='str'),
- from_name=dict(required=False, type='str'),
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- return
-
- def ipspace_get_iter(self, name):
- """
- Return net-ipspaces-get-iter query results
- :param name: Name of the ipspace
- :return: NaElement if ipspace found, None otherwise
- """
- ipspace_get_iter = netapp_utils.zapi.NaElement('net-ipspaces-get-iter')
- query_details = netapp_utils.zapi.NaElement.create_node_with_children(
- 'net-ipspaces-info', **{'ipspace': name})
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- ipspace_get_iter.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(
- ipspace_get_iter, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- # Error 14636 denotes an ipspace does not exist
- # Error 13073 denotes an ipspace not found
- if to_native(error.code) == "14636" or to_native(error.code) == "13073":
- return None
- else:
- self.module.self.fail_json(
- msg=to_native(error),
- exception=traceback.format_exc())
- return result
-
- def get_ipspace(self, name=None):
- """
- Fetch details if ipspace exists
- :param name: Name of the ipspace to be fetched
- :return:
- Dictionary of current details if ipspace found
- None if ipspace is not found
- """
- if name is None:
- name = self.parameters['name']
- ipspace_get = self.ipspace_get_iter(name)
- if (ipspace_get and ipspace_get.get_child_by_name('num-records') and
- int(ipspace_get.get_child_content('num-records')) >= 1):
- current_ipspace = dict()
- attr_list = ipspace_get.get_child_by_name('attributes-list')
- attr = attr_list.get_child_by_name('net-ipspaces-info')
- current_ipspace['name'] = attr.get_child_content('ipspace')
- return current_ipspace
- return None
-
- def create_ipspace(self):
- """
- Create ipspace
- :return: None
- """
- ipspace_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'net-ipspaces-create', **{'ipspace': self.parameters['name']})
- try:
- self.server.invoke_successfully(ipspace_create,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.self.fail_json(
- msg="Error provisioning ipspace %s: %s" % (
- self.parameters['name'],
- to_native(error)),
- exception=traceback.format_exc())
-
- def delete_ipspace(self):
- """
- Destroy ipspace
- :return: None
- """
- ipspace_destroy = netapp_utils.zapi.NaElement.create_node_with_children(
- 'net-ipspaces-destroy',
- **{'ipspace': self.parameters['name']})
- try:
- self.server.invoke_successfully(
- ipspace_destroy, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.self.fail_json(
- msg="Error removing ipspace %s: %s" % (
- self.parameters['name'],
- to_native(error)),
- exception=traceback.format_exc())
-
- def rename_ipspace(self):
- """
- Rename an ipspace
- :return: Nothing
- """
- ipspace_rename = netapp_utils.zapi.NaElement.create_node_with_children(
- 'net-ipspaces-rename',
- **{'ipspace': self.parameters['from_name'],
- 'new-name': self.parameters['name']})
- try:
- self.server.invoke_successfully(ipspace_rename,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(
- msg="Error renaming ipspace %s: %s" % (
- self.parameters['from_name'],
- to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Apply action to the ipspace
- :return: Nothing
- """
- current = self.get_ipspace()
- # rename and create are mutually exclusive
- rename, cd_action = None, None
- if self.parameters.get('from_name'):
- rename = self.na_helper.is_rename_action(
- self.get_ipspace(self.parameters['from_name']),
- current)
- if rename is None:
- self.module.fail_json(
- msg="Error renaming: ipspace %s does not exist" %
- self.parameters['from_name'])
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_ipspace()
- elif cd_action == 'create':
- self.create_ipspace()
- elif cd_action == 'delete':
- self.delete_ipspace()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Execute action
- :return: nothing
- """
- obj = NetAppOntapIpspace()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_iscsi.py b/lib/ansible/modules/storage/netapp/na_ontap_iscsi.py
deleted file mode 100644
index 07dcbed78e..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_iscsi.py
+++ /dev/null
@@ -1,272 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2017-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_iscsi
-
-short_description: NetApp ONTAP manage iSCSI service
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- create, delete, start, stop iSCSI service on SVM.
-
-options:
-
- state:
- description:
- - Whether the service should be present or deleted.
- choices: ['present', 'absent']
- default: present
-
- service_state:
- description:
- - Whether the specified service should running .
- choices: ['started', 'stopped']
-
- vserver:
- required: true
- description:
- - The name of the vserver to use.
-
-'''
-
-EXAMPLES = """
-- name: Create iscsi service
- na_ontap_iscsi:
- state: present
- service_state: started
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-- name: Stop Iscsi service
- na_ontap_iscsi:
- state: present
- service_state: stopped
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-- name: Delete Iscsi service
- na_ontap_iscsi:
- state: absent
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapISCSI(object):
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- service_state=dict(required=False, choices=[
- 'started', 'stopped'], default=None),
- vserver=dict(required=True, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- params = self.module.params
-
- # set up state variables
- self.state = params['state']
- self.service_state = params['service_state']
- if self.state == 'present' and self.service_state is None:
- self.service_state = 'started'
- self.vserver = params['vserver']
- self.is_started = None
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=self.vserver)
-
- def get_iscsi(self):
- """
- Return details about the iscsi service
-
- :return: Details about the iscsi service
- :rtype: dict
- """
- iscsi_info = netapp_utils.zapi.NaElement('iscsi-service-get-iter')
- iscsi_attributes = netapp_utils.zapi.NaElement('iscsi-service-info')
-
- iscsi_attributes.add_new_child('vserver', self.vserver)
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(iscsi_attributes)
-
- iscsi_info.add_child_elem(query)
-
- result = self.server.invoke_successfully(iscsi_info, True)
- return_value = None
-
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) >= 1:
-
- iscsi = result.get_child_by_name(
- 'attributes-list').get_child_by_name('iscsi-service-info')
- if iscsi:
- is_started = iscsi.get_child_content('is-available') == 'true'
- return_value = {
- 'is_started': is_started
- }
-
- return return_value
-
- def create_iscsi_service(self):
- """
- Create iscsi service and start if requested
- """
- iscsi_service = netapp_utils.zapi.NaElement.create_node_with_children(
- 'iscsi-service-create',
- **{'start': 'true' if self.state == 'started' else 'false'
- })
-
- try:
- self.server.invoke_successfully(
- iscsi_service, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error creating iscsi service: % s"
- % (to_native(e)),
- exception=traceback.format_exc())
-
- def delete_iscsi_service(self):
- """
- Delete the iscsi service
- """
- if self.is_started:
- self.stop_iscsi_service()
-
- iscsi_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'iscsi-service-destroy')
-
- try:
- self.server.invoke_successfully(
- iscsi_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error deleting iscsi service \
- on vserver %s: %s"
- % (self.vserver, to_native(e)),
- exception=traceback.format_exc())
-
- def stop_iscsi_service(self):
- """
- Stop iscsi service
- """
-
- iscsi_stop = netapp_utils.zapi.NaElement.create_node_with_children(
- 'iscsi-service-stop')
-
- try:
- self.server.invoke_successfully(iscsi_stop, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error Stopping iscsi service \
- on vserver %s: %s"
- % (self.vserver, to_native(e)),
- exception=traceback.format_exc())
-
- def start_iscsi_service(self):
- """
- Start iscsi service
- """
- iscsi_start = netapp_utils.zapi.NaElement.create_node_with_children(
- 'iscsi-service-start')
-
- try:
- self.server.invoke_successfully(iscsi_start, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error starting iscsi service \
- on vserver %s: %s"
- % (self.vserver, to_native(e)),
- exception=traceback.format_exc())
-
- def apply(self):
- property_changed = False
- iscsi_service_exists = False
- netapp_utils.ems_log_event("na_ontap_iscsi", self.server)
- iscsi_service_detail = self.get_iscsi()
-
- if iscsi_service_detail:
- self.is_started = iscsi_service_detail['is_started']
- iscsi_service_exists = True
-
- if self.state == 'absent':
- property_changed = True
-
- elif self.state == 'present':
- is_started = 'started' if self.is_started else 'stopped'
- property_changed = is_started != self.service_state
-
- else:
- if self.state == 'present':
- property_changed = True
-
- if property_changed:
- if self.module.check_mode:
- pass
- else:
- if self.state == 'present':
- if not iscsi_service_exists:
- self.create_iscsi_service() # the service is stopped when initially created
- if self.service_state == 'started':
- self.start_iscsi_service()
- if iscsi_service_exists and self.service_state == 'stopped':
- self.stop_iscsi_service()
-
- elif self.state == 'absent':
- self.delete_iscsi_service()
-
- changed = property_changed
- # TODO: include other details about the lun (size, etc.)
- self.module.exit_json(changed=changed)
-
-
-def main():
- v = NetAppOntapISCSI()
- v.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_job_schedule.py b/lib/ansible/modules/storage/netapp/na_ontap_job_schedule.py
deleted file mode 100644
index 30b7f885b2..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_job_schedule.py
+++ /dev/null
@@ -1,297 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-module: na_ontap_job_schedule
-short_description: NetApp ONTAP Job Schedule
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create/Delete/Modify job-schedules on ONTAP
-options:
- state:
- description:
- - Whether the specified job schedule should exist or not.
- choices: ['present', 'absent']
- default: present
- name:
- description:
- - The name of the job-schedule to manage.
- required: true
- job_minutes:
- description:
- - The minute(s) of each hour when the job should be run.
- Job Manager cron scheduling minute.
- -1 represents all minutes and is
- only supported for cron schedule create and modify.
- Range is [-1..59]
- type: list
- job_hours:
- version_added: '2.8'
- description:
- - The hour(s) of the day when the job should be run.
- Job Manager cron scheduling hour.
- -1 represents all hours and is
- only supported for cron schedule create and modify.
- Range is [-1..23]
- type: list
- job_months:
- version_added: '2.8'
- description:
- - The month(s) when the job should be run.
- Job Manager cron scheduling month.
- -1 represents all months and is
- only supported for cron schedule create and modify.
- Range is [-1..11]
- type: list
- job_days_of_month:
- version_added: '2.8'
- description:
- - The day(s) of the month when the job should be run.
- Job Manager cron scheduling day of month.
- -1 represents all days of a month from 1 to 31, and is
- only supported for cron schedule create and modify.
- Range is [-1..31]
- type: list
- job_days_of_week:
- version_added: '2.8'
- description:
- - The day(s) in the week when the job should be run.
- Job Manager cron scheduling day of week.
- Zero represents Sunday. -1 represents all days of a week and is
- only supported for cron schedule create and modify.
- Range is [-1..6]
- type: list
-'''
-
-EXAMPLES = """
- - name: Create Job for 11.30PM at 10th of every month
- na_ontap_job_schedule:
- state: present
- name: jobName
- job_minutes: 30
- job_hours: 23
- job_days_of_month: 10
- job_months: -1
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Delete Job
- na_ontap_job_schedule:
- state: absent
- name: jobName
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-
-"""
-
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPJob(object):
- '''Class with job schedule cron methods'''
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- job_minutes=dict(required=False, type='list'),
- job_months=dict(required=False, type='list'),
- job_hours=dict(required=False, type='list'),
- job_days_of_month=dict(required=False, type='list'),
- job_days_of_week=dict(required=False, type='list')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- self.set_playbook_zapi_key_map()
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def set_playbook_zapi_key_map(self):
- self.na_helper.zapi_string_keys = {
- 'name': 'job-schedule-name',
- }
- self.na_helper.zapi_list_keys = {
- 'job_minutes': ('job-schedule-cron-minute', 'cron-minute'),
- 'job_months': ('job-schedule-cron-month', 'cron-month'),
- 'job_hours': ('job-schedule-cron-hour', 'cron-hour'),
- 'job_days_of_month': ('job-schedule-cron-day', 'cron-day-of-month'),
- 'job_days_of_week': ('job-schedule-cron-day-of-week', 'cron-day-of-week')
- }
-
- def get_job_schedule(self):
- """
- Return details about the job
- :param:
- name : Job name
- :return: Details about the Job. None if not found.
- :rtype: dict
- """
- job_get_iter = netapp_utils.zapi.NaElement('job-schedule-cron-get-iter')
- job_get_iter.translate_struct({
- 'query': {
- 'job-schedule-cron-info': {
- 'job-schedule-name': self.parameters['name']
- }
- }
- })
- result = self.server.invoke_successfully(job_get_iter, True)
- job_details = None
- # check if job exists
- if result.get_child_by_name('num-records') and int(result['num-records']) >= 1:
- job_info = result['attributes-list']['job-schedule-cron-info']
- job_details = dict()
- for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
- job_details[item_key] = job_info[zapi_key]
- for item_key, zapi_key in self.na_helper.zapi_list_keys.items():
- parent, dummy = zapi_key
- job_details[item_key] = self.na_helper.get_value_for_list(from_zapi=True,
- zapi_parent=job_info.get_child_by_name(parent)
- )
- # if any of the job_hours, job_minutes, job_months, job_days are empty:
- # it means the value is -1 for ZAPI
- if not job_details[item_key]:
- job_details[item_key] = ['-1']
- return job_details
-
- def add_job_details(self, na_element_object, values):
- """
- Add children node for create or modify NaElement object
- :param na_element_object: modify or create NaElement object
- :param values: dictionary of cron values to be added
- :return: None
- """
- for item_key in values:
- if item_key in self.na_helper.zapi_string_keys:
- zapi_key = self.na_helper.zapi_string_keys.get(item_key)
- na_element_object[zapi_key] = values[item_key]
- elif item_key in self.na_helper.zapi_list_keys:
- parent_key, child_key = self.na_helper.zapi_list_keys.get(item_key)
- na_element_object.add_child_elem(self.na_helper.get_value_for_list(from_zapi=False,
- zapi_parent=parent_key,
- zapi_child=child_key,
- data=values.get(item_key)))
-
- def create_job_schedule(self):
- """
- Creates a job schedule
- """
- # job_minutes is mandatory for create
- if self.parameters.get('job_minutes') is None:
- self.module.fail_json(msg='Error: missing required parameter job_minutes for create')
-
- job_schedule_create = netapp_utils.zapi.NaElement('job-schedule-cron-create')
- self.add_job_details(job_schedule_create, self.parameters)
- try:
- self.server.invoke_successfully(job_schedule_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating job schedule %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_job_schedule(self):
- """
- Delete a job schedule
- """
- job_schedule_delete = netapp_utils.zapi.NaElement('job-schedule-cron-destroy')
- self.add_job_details(job_schedule_delete, self.parameters)
- try:
- self.server.invoke_successfully(job_schedule_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting job schedule %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_job_schedule(self, params):
- """
- modify a job schedule
- """
- job_schedule_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'job-schedule-cron-modify', **{'job-schedule-name': self.parameters['name']})
- self.add_job_details(job_schedule_modify, params)
- try:
- self.server.invoke_successfully(job_schedule_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying job schedule %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- """
- Autosupport log for job_schedule
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_job_schedule", cserver)
-
- def apply(self):
- """
- Apply action to job-schedule
- """
- self.autosupport_log()
- current = self.get_job_schedule()
- action = self.na_helper.get_cd_action(current, self.parameters)
- if action is None and self.parameters['state'] == 'present':
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if action == 'create':
- self.create_job_schedule()
- elif action == 'delete':
- self.delete_job_schedule()
- elif modify:
- self.modify_job_schedule(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- '''Execute action'''
- job_obj = NetAppONTAPJob()
- job_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_kerberos_realm.py b/lib/ansible/modules/storage/netapp/na_ontap_kerberos_realm.py
deleted file mode 100644
index 26bfc32005..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_kerberos_realm.py
+++ /dev/null
@@ -1,318 +0,0 @@
-#!/usr/bin/python
-'''
-(c) 2019, Red Hat, Inc
-GNU General Public License v3.0+
-(see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-'''
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-
-module: na_ontap_kerberos_realm
-
-short_description: NetApp ONTAP vserver nfs kerberos realm
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: Milan Zink (@zeten30) <zeten30@gmail.com>,<mzink@redhat.com>
-
-description:
-- Create, modify or delete vserver kerberos realm configuration
-
-options:
-
- state:
- description:
- - Whether the Kerberos realm is present or absent.
- choices: ['present', 'absent']
- default: 'present'
- type: str
-
- vserver:
- description:
- - vserver/svm with kerberos realm configured
- required: true
- type: str
-
- realm:
- description:
- - Kerberos realm name
- required: true
- type: str
-
- kdc_vendor:
- description:
- - The vendor of the Key Distribution Centre (KDC) server
- - Required if I(state=present)
- choices: ['Other', 'Microsoft']
- type: str
-
- kdc_ip:
- description:
- - IP address of the Key Distribution Centre (KDC) server
- - Required if I(state=present)
- type: str
-
- kdc_port:
- description:
- - TCP port on the KDC to be used for Kerberos communication.
- - The default for this parameter is '88'.
- type: str
-
- clock_skew:
- description:
- - The clock skew in minutes is the tolerance for accepting tickets with time stamps that do not exactly match the host's system clock.
- - The default for this parameter is '5' minutes.
- type: str
-
- comment:
- description:
- - Optional comment
- type: str
-
- admin_server_ip:
- description:
- - IP address of the host where the Kerberos administration daemon is running. This is usually the master KDC.
- - If this parameter is omitted, the address specified in kdc_ip is used.
- type: str
-
- admin_server_port:
- description:
- - The TCP port on the Kerberos administration server where the Kerberos administration service is running.
- - The default for this parameter is '749'
- type: str
-
- pw_server_ip:
- description:
- - IP address of the host where the Kerberos password-changing server is running.
- - Typically, this is the same as the host indicated in the adminserver-ip.
- - If this parameter is omitted, the IP address in kdc-ip is used.
- type: str
-
- pw_server_port:
- description:
- - The TCP port on the Kerberos password-changing server where the Kerberos password-changing service is running.
- - The default for this parameter is '464'.
- type: str
-'''
-
-EXAMPLES = '''
-
- - name: Create kerberos realm
- na_ontap_kerberos_realm:
- state: present
- realm: 'EXAMPLE.COM'
- vserver: 'vserver1'
- kdc_ip: '1.2.3.4'
- kdc_vendor: 'Other'
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-'''
-
-RETURN = '''
-'''
-
-import traceback
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils._text import to_native
-from ansible.module_utils.basic import AnsibleModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapKerberosRealm(object):
- '''
- Kerberos Realm definition class
- '''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- admin_server_ip=dict(required=False, default=None, type='str'),
- admin_server_port=dict(required=False, default=None, type='str'),
- clock_skew=dict(required=False, default=None, type='str'),
- comment=dict(required=False, default=None, type='str'),
- kdc_ip=dict(required_if=[["state", "present"]], default=None, type='str'),
- kdc_port=dict(required=False, default=None, type='str'),
- kdc_vendor=dict(required_if=[["state", "present"]], default=None, type='str', choices=['Microsoft', 'Other']),
- pw_server_ip=dict(required=False, default=None, type='str'),
- pw_server_port=dict(required=False, default=None, type='str'),
- realm=dict(required=True, type='str'),
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True,
- required_if=[('state', 'present', ['kdc_vendor', 'kdc_ip'])],
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- self.simple_attributes = [
- 'admin_server_ip',
- 'admin_server_port',
- 'clock_skew',
- 'kdc_ip',
- 'kdc_port',
- 'kdc_vendor',
- ]
-
- def get_krbrealm(self, realm_name=None, vserver_name=None):
- '''
- Checks if Kerberos Realm config exists.
-
- :return:
- kerberos realm object if found
- None if not found
- :rtype: object/None
- '''
- # Make query
- krbrealm_info = netapp_utils.zapi.NaElement('kerberos-realm-get-iter')
-
- if realm_name is None:
- realm_name = self.parameters['realm']
-
- if vserver_name is None:
- vserver_name = self.parameters['vserver']
-
- query_details = netapp_utils.zapi.NaElement.create_node_with_children('kerberos-realm', **{'realm': realm_name, 'vserver-name': vserver_name})
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- krbrealm_info.add_child_elem(query)
-
- result = self.server.invoke_successfully(krbrealm_info, enable_tunneling=True)
-
- # Get Kerberos Realm details
- krbrealm_details = None
- if (result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1):
- attributes_list = result.get_child_by_name('attributes-list')
- config_info = attributes_list.get_child_by_name('kerberos-realm')
-
- krbrealm_details = {
- 'admin_server_ip': config_info.get_child_content('admin-server-ip'),
- 'admin_server_port': config_info.get_child_content('admin-server-port'),
- 'clock_skew': config_info.get_child_content('clock-skew'),
- 'kdc_ip': config_info.get_child_content('kdc-ip'),
- 'kdc_port': config_info.get_child_content('kdc-port'),
- 'kdc_vendor': config_info.get_child_content('kdc-vendor'),
- 'pw_server_ip': config_info.get_child_content('password-server-ip'),
- 'pw_server_port': config_info.get_child_content('password-server-port'),
- 'realm': config_info.get_child_content('realm'),
- 'vserver': config_info.get_child_content('vserver'),
- }
-
- return krbrealm_details
-
- def create_krbrealm(self):
- '''supported
- Create Kerberos Realm configuration
- '''
- options = {
- 'realm': self.parameters['realm']
- }
-
- # Other options/attributes
- for attribute in self.simple_attributes:
- if self.parameters.get(attribute) is not None:
- options[str(attribute).replace('_', '-')] = self.parameters[attribute]
-
- if self.parameters.get('pw_server_ip') is not None:
- options['password-server-ip'] = self.parameters['pw_server_ip']
- if self.parameters.get('pw_server_port') is not None:
- options['password-server-port'] = self.parameters['pw_server_port']
-
- # Initialize NaElement
- krbrealm_create = netapp_utils.zapi.NaElement.create_node_with_children('kerberos-realm-create', **options)
-
- # Try to create Kerberos Realm configuration
- try:
- self.server.invoke_successfully(krbrealm_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as errcatch:
- self.module.fail_json(msg='Error creating Kerberos Realm configuration %s: %s' % (self.parameters['realm'], to_native(errcatch)),
- exception=traceback.format_exc())
-
- def delete_krbrealm(self):
- '''
- Delete Kerberos Realm configuration
- '''
- krbrealm_delete = netapp_utils.zapi.NaElement.create_node_with_children('kerberos-realm-delete', **{'realm': self.parameters['realm']})
-
- try:
- self.server.invoke_successfully(krbrealm_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as errcatch:
- self.module.fail_json(msg='Error deleting Kerberos Realm configuration %s: %s' % (
- self.parameters['realm'], to_native(errcatch)), exception=traceback.format_exc())
-
- def modify_krbrealm(self, modify):
- '''
- Modify Kerberos Realm
- :param modify: list of modify attributes
- '''
- krbrealm_modify = netapp_utils.zapi.NaElement('kerberos-realm-modify')
- krbrealm_modify.add_new_child('realm', self.parameters['realm'])
-
- for attribute in modify:
- if attribute in self.simple_attributes:
- krbrealm_modify.add_new_child(str(attribute).replace('_', '-'), self.parameters[attribute])
- if attribute == 'pw_server_ip':
- krbrealm_modify.add_new_child('password-server-ip', self.parameters['pw_server_ip'])
- if attribute == 'pw_server_port':
- krbrealm_modify.add_new_child('password-server-port', self.parameters['pw_server_port'])
-
- # Try to modify Kerberos Realm
- try:
- self.server.invoke_successfully(krbrealm_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as errcatch:
- self.module.fail_json(msg='Error modifying Kerberos Realm %s: %s' % (self.parameters['realm'], to_native(errcatch)),
- exception=traceback.format_exc())
-
- def apply(self):
- '''Call create/modify/delete operations.'''
- current = self.get_krbrealm()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- # create an ems log event for users with auto support turned on
- netapp_utils.ems_log_event("na_ontap_kerberos_realm", self.server)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_krbrealm()
- elif cd_action == 'delete':
- self.delete_krbrealm()
- elif modify:
- self.modify_krbrealm(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-#
-# MAIN
-#
-def main():
- '''ONTAP Kerberos Realm'''
- krbrealm = NetAppOntapKerberosRealm()
- krbrealm.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_ldap.py b/lib/ansible/modules/storage/netapp/na_ontap_ldap.py
deleted file mode 100644
index 136bd1e974..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_ldap.py
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/python
-'''
-(c) 2018-2019, NetApp, Inc
-GNU General Public License v3.0+
-(see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-'''
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-
-module: na_ontap_ldap
-
-short_description: NetApp ONTAP LDAP
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: Milan Zink (@zeten30) <zeten30@gmail.com>/<mzink@redhat.com>
-
-description:
-- Create, modify or delete LDAP on NetApp ONTAP SVM/vserver
-
-options:
-
- state:
- description:
- - Whether the LDAP is present or not.
- choices: ['present', 'absent']
- default: 'present'
- type: str
-
- vserver:
- description:
- - vserver/svm configured to use LDAP
- required: true
- type: str
-
- name:
- description:
- - The name of LDAP client configuration
- required: true
- type: str
-
- skip_config_validation:
- description:
- - Skip LDAP validation
- choices: ['true', 'false']
- type: str
-'''
-
-EXAMPLES = '''
-
- - name: Enable LDAP on SVM
- na_ontap_ldap:
- state: present
- name: 'example_ldap'
- vserver: 'vserver1'
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-'''
-
-RETURN = '''
-'''
-
-import traceback
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapLDAP(object):
- '''
- LDAP Client definition class
- '''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- name=dict(required=True, type='str'),
- skip_config_validation=dict(required=False, default=None, choices=['true', 'false']),
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_ldap(self, client_config_name=None):
- '''
- Checks if LDAP config exists.
-
- :return:
- ldap config object if found
- None if not found
- :rtype: object/None
- '''
- # Make query
- config_info = netapp_utils.zapi.NaElement('ldap-config-get-iter')
-
- if client_config_name is None:
- client_config_name = self.parameters['name']
-
- query_details = netapp_utils.zapi.NaElement.create_node_with_children('ldap-config', **{'client-config': client_config_name})
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- config_info.add_child_elem(query)
-
- result = self.server.invoke_successfully(config_info, enable_tunneling=True)
-
- # Get LDAP configuration details
- config_details = None
- if (result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1):
- attributes_list = result.get_child_by_name('attributes-list')
- config_info = attributes_list.get_child_by_name('ldap-config')
-
- # Define config details structure
- config_details = {'client_config': config_info.get_child_content('client-config'),
- 'skip_config_validation': config_info.get_child_content('skip-config-validation'),
- 'vserver': config_info.get_child_content('vserver')}
-
- return config_details
-
- def create_ldap(self):
- '''
- Create LDAP configuration
- '''
- options = {
- 'client-config': self.parameters['name'],
- 'client-enabled': 'true'
- }
-
- if self.parameters.get('skip_config_validation') is not None:
- options['skip-config-validation'] = self.parameters['skip_config_validation']
-
- # Initialize NaElement
- ldap_create = netapp_utils.zapi.NaElement.create_node_with_children('ldap-config-create', **options)
-
- # Try to create LDAP configuration
- try:
- self.server.invoke_successfully(ldap_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as errcatch:
- self.module.fail_json(msg='Error creating LDAP configuration %s: %s' % (self.parameters['name'], to_native(errcatch)),
- exception=traceback.format_exc())
-
- def delete_ldap(self):
- '''
- Delete LDAP configuration
- '''
- ldap_client_delete = netapp_utils.zapi.NaElement.create_node_with_children('ldap-config-delete', **{})
-
- try:
- self.server.invoke_successfully(ldap_client_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as errcatch:
- self.module.fail_json(msg='Error deleting LDAP configuration %s: %s' % (
- self.parameters['name'], to_native(errcatch)), exception=traceback.format_exc())
-
- def modify_ldap(self, modify):
- '''
- Modify LDAP
- :param modify: list of modify attributes
- '''
- ldap_modify = netapp_utils.zapi.NaElement('ldap-config-modify')
- ldap_modify.add_new_child('client-config', self.parameters['name'])
-
- for attribute in modify:
- if attribute == 'skip_config_validation':
- ldap_modify.add_new_child('skip-config-validation', self.parameters[attribute])
-
- # Try to modify LDAP
- try:
- self.server.invoke_successfully(ldap_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as errcatch:
- self.module.fail_json(msg='Error modifying LDAP %s: %s' % (self.parameters['name'], to_native(errcatch)),
- exception=traceback.format_exc())
-
- def apply(self):
- '''Call create/modify/delete operations.'''
- current = self.get_ldap()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- # create an ems log event for users with auto support turned on
- netapp_utils.ems_log_event("na_ontap_ldap", self.server)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_ldap()
- elif cd_action == 'delete':
- self.delete_ldap()
- elif modify:
- self.modify_ldap(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-#
-# MAIN
-#
-def main():
- '''ONTAP LDAP client configuration'''
- ldapclient = NetAppOntapLDAP()
- ldapclient.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_ldap_client.py b/lib/ansible/modules/storage/netapp/na_ontap_ldap_client.py
deleted file mode 100644
index 584274acbe..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_ldap_client.py
+++ /dev/null
@@ -1,359 +0,0 @@
-#!/usr/bin/python
-'''
-(c) 2018-2019, NetApp, Inc
-GNU General Public License v3.0+
-(see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-'''
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-
-module: na_ontap_ldap_client
-
-short_description: NetApp ONTAP LDAP client
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: Milan Zink (@zeten30) <zeten30@gmail.com>/<mzink@redhat.com>
-
-description:
-- Create, modify or delete LDAP client on NetApp ONTAP
-
-options:
-
- state:
- description:
- - Whether the specified LDAP client configuration exist or not.
- choices: ['present', 'absent']
- default: 'present'
- type: str
-
- vserver:
- description:
- - vserver/svm that holds LDAP client configuration
- required: true
- type: str
-
- name:
- description:
- - The name of LDAP client configuration
- required: true
- type: str
-
- ldap_servers:
- description:
- - Comma separated list of LDAP servers. FQDN's or IP addresses
- - Required if I(state=present).
- type: list
-
- schema:
- description:
- - LDAP schema
- - Required if I(state=present).
- choices: ['AD-IDMU', 'AD-SFU', 'MS-AD-BIS', 'RFC-2307']
- type: str
-
- base_dn:
- description:
- - LDAP base DN
- type: str
-
- base_scope:
- description:
- - LDAP search scope
- choices: ['subtree', 'onelevel', 'base']
- type: str
-
- port:
- description:
- - LDAP server port
- type: int
-
- query_timeout:
- description:
- - LDAP server query timeout
- type: int
-
- min_bind_level:
- description:
- - Minimal LDAP server bind level.
- choices: ['anonymous', 'simple', 'sasl']
- type: str
-
- bind_dn:
- description:
- - LDAP bind user DN
- type: str
-
- bind_password:
- description:
- - LDAP bind user password
- type: str
-
- use_start_tls:
- description:
- - Start TLS on LDAP connection
- choices: ['true', 'false']
- type: str
-
- referral_enabled:
- description:
- - LDAP Referral Chasing
- choices: ['true', 'false']
- type: str
-
- session_security:
- description:
- - Client Session Security
- choices: ['true', 'false']
- type: str
-'''
-
-EXAMPLES = '''
-
- - name: Create LDAP client
- na_ontap_ldap_client:
- state: present
- name: 'example_ldap'
- vserver: 'vserver1'
- ldap_servers: 'ldap1.example.company.com,ldap2.example.company.com'
- base_dn: 'dc=example,dc=company,dc=com'
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-'''
-
-RETURN = '''
-'''
-
-import traceback
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapLDAPClient(object):
- '''
- LDAP Client definition class
- '''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- base_dn=dict(required=False, type='str'),
- base_scope=dict(required=False, default=None, choices=['subtree', 'onelevel', 'base']),
- bind_dn=dict(required=False, default=None, type='str'),
- bind_password=dict(type='str', required=False, default=None, no_log=True),
- name=dict(required=True, type='str'),
- ldap_servers=dict(required_if=[["state", "present"]], type='list'),
- min_bind_level=dict(required=False, default=None, choices=['anonymous', 'simple', 'sasl']),
- port=dict(required=False, default=None, type='int'),
- query_timeout=dict(required=False, default=None, type='int'),
- referral_enabled=dict(required=False, default=None, choices=['true', 'false']),
- schema=dict(required_if=[["state", "present"]], default=None, type='str', choices=['AD-IDMU', 'AD-SFU', 'MS-AD-BIS', 'RFC-2307']),
- session_security=dict(required=False, default=None, choices=['true', 'false']),
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- use_start_tls=dict(required=False, default=None, choices=['true', 'false']),
- vserver=dict(required=True, type='str')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True,
- required_if=[('state', 'present', ['ldap_servers', 'schema'])],
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- self.simple_attributes = [
- 'base_dn',
- 'base_scope',
- 'bind_dn',
- 'bind_password',
- 'min_bind_level',
- 'port',
- 'query_timeout',
- 'referral_enabled',
- 'session_security',
- 'use_start_tls'
- ]
-
- def get_ldap_client(self, client_config_name=None, vserver_name=None):
- '''
- Checks if LDAP client config exists.
-
- :return:
- ldap client config object if found
- None if not found
- :rtype: object/None
- '''
- # Make query
- client_config_info = netapp_utils.zapi.NaElement('ldap-client-get-iter')
-
- if client_config_name is None:
- client_config_name = self.parameters['name']
-
- if vserver_name is None:
- vserver_name = '*'
-
- query_details = netapp_utils.zapi.NaElement.create_node_with_children('ldap-client',
- **{'ldap-client-config': client_config_name, 'vserver': vserver_name})
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- client_config_info.add_child_elem(query)
-
- result = self.server.invoke_successfully(client_config_info, enable_tunneling=False)
-
- # Get LDAP client configuration details
- client_config_details = None
- if (result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1):
- attributes_list = result.get_child_by_name('attributes-list')
- client_config_info = attributes_list.get_child_by_name('ldap-client')
-
- # Get LDAP servers list
- ldap_server_list = list()
- get_list = client_config_info.get_child_by_name('ldap-servers')
- if get_list is not None:
- ldap_servers = get_list.get_children()
- for ldap_server in ldap_servers:
- ldap_server_list.append(ldap_server.get_content())
-
- # Define config details structure
- client_config_details = {'name': client_config_info.get_child_content('ldap-client-config'),
- 'ldap_servers': client_config_info.get_child_content('ldap-servers'),
- 'base_dn': client_config_info.get_child_content('base-dn'),
- 'base_scope': client_config_info.get_child_content('base-scope'),
- 'bind_dn': client_config_info.get_child_content('bind-dn'),
- 'bind_password': client_config_info.get_child_content('bind-password'),
- 'min_bind_level': client_config_info.get_child_content('min-bind-level'),
- 'port': client_config_info.get_child_content('port'),
- 'query_timeout': client_config_info.get_child_content('query-timeout'),
- 'referral_enabled': client_config_info.get_child_content('referral-enabled'),
- 'schema': client_config_info.get_child_content('schema'),
- 'session_security': client_config_info.get_child_content('session-security'),
- 'use_start_tls': client_config_info.get_child_content('use-start-tls'),
- 'vserver': client_config_info.get_child_content('vserver')}
-
- return client_config_details
-
- def create_ldap_client(self):
- '''
- Create LDAP client configuration
- '''
- # LDAP servers NaElement
- ldap_servers_element = netapp_utils.zapi.NaElement('ldap-servers')
-
- # Mandatory options
- for ldap_server_name in self.parameters['ldap_servers']:
- ldap_servers_element.add_new_child('string', ldap_server_name)
-
- options = {
- 'ldap-client-config': self.parameters['name'],
- 'schema': self.parameters['schema'],
- }
-
- # Other options/attributes
- for attribute in self.simple_attributes:
- if self.parameters.get(attribute) is not None:
- options[str(attribute).replace('_', '-')] = self.parameters[attribute]
-
- # Initialize NaElement
- ldap_client_create = netapp_utils.zapi.NaElement.create_node_with_children('ldap-client-create', **options)
- ldap_client_create.add_child_elem(ldap_servers_element)
-
- # Try to create LDAP configuration
- try:
- self.server.invoke_successfully(ldap_client_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as errcatch:
- self.module.fail_json(msg='Error creating LDAP client %s: %s' % (self.parameters['name'], to_native(errcatch)),
- exception=traceback.format_exc())
-
- def delete_ldap_client(self):
- '''
- Delete LDAP client configuration
- '''
- ldap_client_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'ldap-client-delete', **{'ldap-client-config': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(ldap_client_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as errcatch:
- self.module.fail_json(msg='Error deleting LDAP client configuration %s: %s' % (
- self.parameters['name'], to_native(errcatch)), exception=traceback.format_exc())
-
- def modify_ldap_client(self, modify):
- '''
- Modify LDAP client
- :param modify: list of modify attributes
- '''
- ldap_client_modify = netapp_utils.zapi.NaElement('ldap-client-modify')
- ldap_client_modify.add_new_child('ldap-client-config', self.parameters['name'])
-
- for attribute in modify:
- # LDAP_servers
- if attribute == 'ldap_servers':
- ldap_servers_element = netapp_utils.zapi.NaElement('ldap-servers')
- for ldap_server_name in self.parameters['ldap_servers']:
- ldap_servers_element.add_new_child('string', ldap_server_name)
- ldap_client_modify.add_child_elem(ldap_servers_element)
-
- # Simple attributes
- if attribute in self.simple_attributes:
- ldap_client_modify.add_new_child(str(attribute).replace('_', '-'), self.parameters[attribute])
-
- # Try to modify LDAP client
- try:
- self.server.invoke_successfully(ldap_client_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as errcatch:
- self.module.fail_json(msg='Error modifying LDAP client %s: %s' % (self.parameters['name'], to_native(errcatch)),
- exception=traceback.format_exc())
-
- def apply(self):
- '''Call create/modify/delete operations.'''
- current = self.get_ldap_client()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- # create an ems log event for users with auto support turned on
- netapp_utils.ems_log_event("na_ontap_ldap_client", self.server)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_ldap_client()
- elif cd_action == 'delete':
- self.delete_ldap_client()
- elif modify:
- self.modify_ldap_client(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-#
-# MAIN
-#
-def main():
- '''ONTAP LDAP client configuration'''
- ldapclient = NetAppOntapLDAPClient()
- ldapclient.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_license.py b/lib/ansible/modules/storage/netapp/na_ontap_license.py
deleted file mode 100644
index cddcc842e0..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_license.py
+++ /dev/null
@@ -1,326 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_license
-
-short_description: NetApp ONTAP protocol and feature licenses
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Add or remove licenses on NetApp ONTAP.
-
-options:
- state:
- description:
- - Whether the specified license should exist or not.
- choices: ['present', 'absent']
- default: present
-
- remove_unused:
- description:
- - Remove licenses that have no controller affiliation in the cluster.
- type: bool
-
- remove_expired:
- description:
- - Remove licenses that have expired in the cluster.
- type: bool
-
- serial_number:
- description:
- Serial number of the node associated with the license.
- This parameter is used primarily when removing license for a specific service.
-
- license_names:
- description:
- - List of license-names to delete.
- suboptions:
- base:
- description:
- - Cluster Base License
- nfs:
- description:
- - NFS License
- cifs:
- description:
- - CIFS License
- iscsi:
- description:
- - iSCSI License
- fcp:
- description:
- - FCP License
- cdmi:
- description:
- - CDMI License
- snaprestore:
- description:
- - SnapRestore License
- snapmirror:
- description:
- - SnapMirror License
- flexclone:
- description:
- - FlexClone License
- snapvault:
- description:
- - SnapVault License
- snaplock:
- description:
- - SnapLock License
- snapmanagersuite:
- description:
- - SnapManagerSuite License
- snapprotectapps:
- description:
- - SnapProtectApp License
- v_storageattach:
- description:
- - Virtual Attached Storage License
-
- license_codes:
- description:
- - List of license codes to be added.
-
-'''
-
-
-EXAMPLES = """
-- name: Add licenses
- na_ontap_license:
- state: present
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- serial_number: #################
- license_codes: CODE1,CODE2
-
-- name: Remove licenses
- na_ontap_license:
- state: absent
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- remove_unused: false
- remove_expired: true
- serial_number: #################
- license_names: nfs,cifs
-"""
-
-RETURN = """
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-def local_cmp(a, b):
- """
- compares with only values and not keys, keys should be the same for both dicts
- :param a: dict 1
- :param b: dict 2
- :return: difference of values in both dicts
- """
- diff = [key for key in a if a[key] != b[key]]
- return len(diff)
-
-
-class NetAppOntapLicense(object):
- '''ONTAP license class'''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- serial_number=dict(required=False, type='str'),
- remove_unused=dict(default=None, type='bool'),
- remove_expired=dict(default=None, type='bool'),
- license_codes=dict(default=None, type='list'),
- license_names=dict(default=None, type='list'),
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=False,
- required_if=[
- ('state', 'absent', ['serial_number', 'license_names'])]
- )
- parameters = self.module.params
- # set up state variables
- self.state = parameters['state']
- self.serial_number = parameters['serial_number']
- self.remove_unused = parameters['remove_unused']
- self.remove_expired = parameters['remove_expired']
- self.license_codes = parameters['license_codes']
- self.license_names = parameters['license_names']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def get_licensing_status(self):
- """
- Check licensing status
-
- :return: package (key) and licensing status (value)
- :rtype: dict
- """
- license_status = netapp_utils.zapi.NaElement(
- 'license-v2-status-list-info')
- result = None
- try:
- result = self.server.invoke_successfully(license_status,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error checking license status: %s" %
- to_native(error), exception=traceback.format_exc())
-
- return_dictionary = {}
- license_v2_status = result.get_child_by_name('license-v2-status')
- if license_v2_status:
- for license_v2_status_info in license_v2_status.get_children():
- package = license_v2_status_info.get_child_content('package')
- status = license_v2_status_info.get_child_content('method')
- return_dictionary[package] = status
-
- return return_dictionary
-
- def remove_licenses(self, package_name):
- """
- Remove requested licenses
- :param:
- package_name: Name of the license to be deleted
- """
- license_delete = netapp_utils.zapi.NaElement('license-v2-delete')
- license_delete.add_new_child('serial-number', self.serial_number)
- license_delete.add_new_child('package', package_name)
- try:
- self.server.invoke_successfully(license_delete,
- enable_tunneling=False)
- return True
- except netapp_utils.zapi.NaApiError as error:
- # Error 15661 - Object not found
- if to_native(error.code) == "15661":
- return False
- else:
- self.module.fail_json(msg="Error removing license %s" %
- to_native(error), exception=traceback.format_exc())
-
- def remove_unused_licenses(self):
- """
- Remove unused licenses
- """
- remove_unused = netapp_utils.zapi.NaElement('license-v2-delete-unused')
- try:
- self.server.invoke_successfully(remove_unused,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error removing unused licenses: %s" %
- to_native(error), exception=traceback.format_exc())
-
- def remove_expired_licenses(self):
- """
- Remove expired licenses
- """
- remove_expired = netapp_utils.zapi.NaElement(
- 'license-v2-delete-expired')
- try:
- self.server.invoke_successfully(remove_expired,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error removing expired licenses: %s" %
- to_native(error), exception=traceback.format_exc())
-
- def add_licenses(self):
- """
- Add licenses
- """
- license_add = netapp_utils.zapi.NaElement('license-v2-add')
- codes = netapp_utils.zapi.NaElement('codes')
- for code in self.license_codes:
- codes.add_new_child('license-code-v2', str(code.strip().lower()))
- license_add.add_child_elem(codes)
- try:
- self.server.invoke_successfully(license_add,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error adding licenses: %s" %
- to_native(error), exception=traceback.format_exc())
-
- def apply(self):
- '''Call add, delete or modify methods'''
- changed = False
- create_license = False
- remove_license = False
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_license", cserver)
- # Add / Update licenses.
- license_status = self.get_licensing_status()
-
- if self.state == 'absent': # delete
- changed = True
- else: # add or update
- if self.license_codes is not None:
- create_license = True
- changed = True
- if self.remove_unused is not None:
- remove_license = True
- changed = True
- if self.remove_expired is not None:
- remove_license = True
- changed = True
- if changed:
- if self.state == 'present': # execute create
- if create_license:
- self.add_licenses()
- if self.remove_unused is not None:
- self.remove_unused_licenses()
- if self.remove_expired is not None:
- self.remove_expired_licenses()
- if create_license or remove_license:
- new_license_status = self.get_licensing_status()
- if local_cmp(license_status, new_license_status) == 0:
- changed = False
- else: # execute delete
- license_deleted = False
- for package in self.license_names:
- license_deleted |= self.remove_licenses(package)
- changed = license_deleted
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- '''Apply license operations'''
- obj = NetAppOntapLicense()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_lun.py b/lib/ansible/modules/storage/netapp/na_ontap_lun.py
deleted file mode 100644
index 2ab43b1749..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_lun.py
+++ /dev/null
@@ -1,406 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2017, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_lun
-
-short_description: NetApp ONTAP manage LUNs
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create, destroy, resize LUNs on NetApp ONTAP.
-
-options:
-
- state:
- description:
- - Whether the specified LUN should exist or not.
- choices: ['present', 'absent']
- default: present
-
- name:
- description:
- - The name of the LUN to manage.
- required: true
-
- flexvol_name:
- description:
- - The name of the FlexVol the LUN should exist on.
- required: true
-
- size:
- description:
- - The size of the LUN in C(size_unit).
- - Required when C(state=present).
-
- size_unit:
- description:
- - The unit used to interpret the size parameter.
- choices: ['bytes', 'b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb']
- default: 'gb'
-
- force_resize:
- description:
- Forcibly reduce the size. This is required for reducing the size of the LUN to avoid accidentally
- reducing the LUN size.
- type: bool
- default: false
-
- force_remove:
- description:
- - If "true", override checks that prevent a LUN from being destroyed if it is online and mapped.
- - If "false", destroying an online and mapped LUN will fail.
- type: bool
- default: false
-
- force_remove_fenced:
- description:
- - If "true", override checks that prevent a LUN from being destroyed while it is fenced.
- - If "false", attempting to destroy a fenced LUN will fail.
- - The default if not specified is "false". This field is available in Data ONTAP 8.2 and later.
- type: bool
- default: false
-
- vserver:
- required: true
- description:
- - The name of the vserver to use.
-
- ostype:
- description:
- - The os type for the LUN.
- default: 'image'
-
- space_reserve:
- description:
- - This can be set to "false" which will create a LUN without any space being reserved.
- type: bool
- default: True
-
- space_allocation:
- description:
- - This enables support for the SCSI Thin Provisioning features. If the Host and file system do
- not support this do not enable it.
- type: bool
- default: False
- version_added: '2.7'
-
-'''
-
-EXAMPLES = """
-- name: Create LUN
- na_ontap_lun:
- state: present
- name: ansibleLUN
- flexvol_name: ansibleVolume
- vserver: ansibleVServer
- size: 5
- size_unit: mb
- ostype: linux
- space_reserve: True
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-- name: Resize LUN
- na_ontap_lun:
- state: present
- name: ansibleLUN
- force_resize: True
- flexvol_name: ansibleVolume
- vserver: ansibleVServer
- size: 5
- size_unit: gb
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapLUN(object):
-
- def __init__(self):
-
- self._size_unit_map = dict(
- bytes=1,
- b=1,
- kb=1024,
- mb=1024 ** 2,
- gb=1024 ** 3,
- tb=1024 ** 4,
- pb=1024 ** 5,
- eb=1024 ** 6,
- zb=1024 ** 7,
- yb=1024 ** 8
- )
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- size=dict(type='int'),
- size_unit=dict(default='gb',
- choices=['bytes', 'b', 'kb', 'mb', 'gb', 'tb',
- 'pb', 'eb', 'zb', 'yb'], type='str'),
- force_resize=dict(default=False, type='bool'),
- force_remove=dict(default=False, type='bool'),
- force_remove_fenced=dict(default=False, type='bool'),
- flexvol_name=dict(required=True, type='str'),
- vserver=dict(required=True, type='str'),
- ostype=dict(required=False, type='str', default='image'),
- space_reserve=dict(required=False, type='bool', default=True),
- space_allocation=dict(required=False, type='bool', default=False),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('state', 'present', ['size'])
- ],
- supports_check_mode=True
- )
-
- parameters = self.module.params
-
- # set up state variables
- self.state = parameters['state']
- self.name = parameters['name']
- self.size_unit = parameters['size_unit']
- if parameters['size'] is not None:
- self.size = parameters['size'] * self._size_unit_map[self.size_unit]
- else:
- self.size = None
- self.force_resize = parameters['force_resize']
- self.force_remove = parameters['force_remove']
- self.force_remove_fenced = parameters['force_remove_fenced']
- self.flexvol_name = parameters['flexvol_name']
- self.vserver = parameters['vserver']
- self.ostype = parameters['ostype']
- self.space_reserve = parameters['space_reserve']
- self.space_allocation = parameters['space_allocation']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver)
-
- def get_lun(self):
- """
- Return details about the LUN
-
- :return: Details about the lun
- :rtype: dict
- """
-
- luns = []
- tag = None
- while True:
- lun_info = netapp_utils.zapi.NaElement('lun-get-iter')
- if tag:
- lun_info.add_new_child('tag', tag, True)
-
- query_details = netapp_utils.zapi.NaElement('lun-info')
- query_details.add_new_child('vserver', self.vserver)
- query_details.add_new_child('volume', self.flexvol_name)
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
-
- lun_info.add_child_elem(query)
-
- result = self.server.invoke_successfully(lun_info, True)
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- attr_list = result.get_child_by_name('attributes-list')
- luns.extend(attr_list.get_children())
-
- tag = result.get_child_content('next-tag')
-
- if tag is None:
- break
-
- # The LUNs have been extracted.
- # Find the specified lun and extract details.
- return_value = None
- for lun in luns:
- path = lun.get_child_content('path')
- _rest, _splitter, found_name = path.rpartition('/')
-
- if found_name == self.name:
- size = lun.get_child_content('size')
-
- # Find out if the lun is attached
- attached_to = None
- lun_id = None
- if lun.get_child_content('mapped') == 'true':
- lun_map_list = netapp_utils.zapi.NaElement.create_node_with_children(
- 'lun-map-list-info', **{'path': path})
-
- result = self.server.invoke_successfully(
- lun_map_list, enable_tunneling=True)
-
- igroups = result.get_child_by_name('initiator-groups')
- if igroups:
- for igroup_info in igroups.get_children():
- igroup = igroup_info.get_child_content(
- 'initiator-group-name')
- attached_to = igroup
- lun_id = igroup_info.get_child_content('lun-id')
-
- return_value = {
- 'name': found_name,
- 'size': size,
- 'attached_to': attached_to,
- 'lun_id': lun_id
- }
- else:
- continue
-
- return return_value
-
- def create_lun(self):
- """
- Create LUN with requested name and size
- """
- path = '/vol/%s/%s' % (self.flexvol_name, self.name)
- lun_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'lun-create-by-size', **{'path': path,
- 'size': str(self.size),
- 'ostype': self.ostype,
- 'space-reservation-enabled': str(self.space_reserve),
- 'space-allocation-enabled': str(self.space_allocation)})
-
- try:
- self.server.invoke_successfully(lun_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error provisioning lun %s of size %s: %s" % (self.name, self.size, to_native(e)),
- exception=traceback.format_exc())
-
- def delete_lun(self):
- """
- Delete requested LUN
- """
- path = '/vol/%s/%s' % (self.flexvol_name, self.name)
-
- lun_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'lun-destroy', **{'path': path,
- 'force': str(self.force_remove),
- 'destroy-fenced-lun':
- str(self.force_remove_fenced)})
-
- try:
- self.server.invoke_successfully(lun_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error deleting lun %s: %s" % (path, to_native(e)),
- exception=traceback.format_exc())
-
- def resize_lun(self):
- """
- Resize requested LUN.
-
- :return: True if LUN was actually re-sized, false otherwise.
- :rtype: bool
- """
- path = '/vol/%s/%s' % (self.flexvol_name, self.name)
-
- lun_resize = netapp_utils.zapi.NaElement.create_node_with_children(
- 'lun-resize', **{'path': path,
- 'size': str(self.size),
- 'force': str(self.force_resize)})
- try:
- self.server.invoke_successfully(lun_resize, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- if to_native(e.code) == "9042":
- # Error 9042 denotes the new LUN size being the same as the
- # old LUN size. This happens when there's barely any difference
- # in the two sizes. For example, from 8388608 bytes to
- # 8194304 bytes. This should go away if/when the default size
- # requested/reported to/from the controller is changed to a
- # larger unit (MB/GB/TB).
- return False
- else:
- self.module.fail_json(msg="Error resizing lun %s: %s" % (path, to_native(e)),
- exception=traceback.format_exc())
-
- return True
-
- def apply(self):
- property_changed = False
- size_changed = False
- lun_exists = False
- netapp_utils.ems_log_event("na_ontap_lun", self.server)
- lun_detail = self.get_lun()
-
- if lun_detail:
- lun_exists = True
- current_size = lun_detail['size']
-
- if self.state == 'absent':
- property_changed = True
-
- elif self.state == 'present':
- if not int(current_size) == self.size:
- size_changed = True
- property_changed = True
-
- else:
- if self.state == 'present':
- property_changed = True
-
- if property_changed:
- if self.module.check_mode:
- pass
- else:
- if self.state == 'present':
- if not lun_exists:
- self.create_lun()
-
- else:
- if size_changed:
- # Ensure that size was actually changed. Please
- # read notes in 'resize_lun' function for details.
- size_changed = self.resize_lun()
- if not size_changed:
- property_changed = False
-
- elif self.state == 'absent':
- self.delete_lun()
-
- changed = property_changed or size_changed
- # TODO: include other details about the lun (size, etc.)
- self.module.exit_json(changed=changed)
-
-
-def main():
- v = NetAppOntapLUN()
- v.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_lun_copy.py b/lib/ansible/modules/storage/netapp/na_ontap_lun_copy.py
deleted file mode 100644
index 625f3fc698..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_lun_copy.py
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
-module: na_ontap_lun_copy
-
-short_description: NetApp ONTAP copy LUNs
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - Copy LUNs on NetApp ONTAP.
-
-options:
-
- state:
- description:
- - Whether the specified LUN should exist or not.
- choices: ['present']
- default: present
-
- destination_vserver:
- description:
- - Specifies the name of the Vserver that will host the new LUN.
- required: true
-
- destination_path:
- description:
- - Specifies the full path to the new LUN.
- required: true
-
- source_path:
- description:
- - Specifies the full path to the source LUN.
- required: true
-
- source_vserver:
- description:
- - Specifies the name of the vserver hosting the LUN to be copied.
-'''
-
-EXAMPLES = """
-- name: Copy LUN
- na_ontap_lun_copy:
- destination_vserver: ansible
- destination_path: /vol/test/test_copy_dest_dest_new
- source_path: /vol/test/test_copy_1
- source_vserver: ansible
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-from ansible.module_utils.netapp_module import NetAppModule
-import ansible.module_utils.netapp as netapp_utils
-
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapLUNCopy(object):
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present'], default='present'),
- destination_vserver=dict(required=True, type='str'),
- destination_path=dict(required=True, type='str'),
- source_path=dict(required=True, type='str'),
- source_vserver=dict(required=False, type='str'),
-
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['destination_vserver'])
-
- def get_lun(self):
- """
- Check if the LUN exists
-
- :return: true is it exists, false otherwise
- :rtype: bool
- """
-
- return_value = False
- lun_info = netapp_utils.zapi.NaElement('lun-get-iter')
- query_details = netapp_utils.zapi.NaElement('lun-info')
-
- query_details.add_new_child('path', self.parameters['destination_path'])
- query_details.add_new_child('vserver', self.parameters['destination_vserver'])
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
-
- lun_info.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(lun_info, True)
-
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error getting lun info %s for verver %s: %s" %
- (self.parameters['destination_path'], self.parameters['destination_vserver'], to_native(e)),
- exception=traceback.format_exc())
-
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- return_value = True
- return return_value
-
- def copy_lun(self):
- """
- Copy LUN with requested path and vserver
- """
- lun_copy = netapp_utils.zapi.NaElement.create_node_with_children(
- 'lun-copy-start', **{'source-vserver': self.parameters['source_vserver']})
-
- path_obj = netapp_utils.zapi.NaElement('paths')
- pair = netapp_utils.zapi.NaElement('lun-path-pair')
- pair.add_new_child('destination-path', self.parameters['destination_path'])
- pair.add_new_child('source-path', self.parameters['source_path'])
- path_obj.add_child_elem(pair)
- lun_copy.add_child_elem(path_obj)
-
- try:
- self.server.invoke_successfully(lun_copy, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error copying lun from %s to vserver %s: %s" %
- (self.parameters['source_vserver'], self.parameters['destination_vserver'], to_native(e)),
- exception=traceback.format_exc())
-
- def apply(self):
-
- netapp_utils.ems_log_event("na_ontap_lun_copy", self.server)
- if self.get_lun(): # lun already exists at destination
- changed = False
- else:
- changed = True
- if self.module.check_mode:
- pass
- else:
- # need to copy lun
- if self.parameters['state'] == 'present':
- self.copy_lun()
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- v = NetAppOntapLUNCopy()
- v.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_lun_map.py b/lib/ansible/modules/storage/netapp/na_ontap_lun_map.py
deleted file mode 100644
index f46f7fea07..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_lun_map.py
+++ /dev/null
@@ -1,282 +0,0 @@
-#!/usr/bin/python
-
-""" this is lun mapping module
-
- (c) 2018-2019, NetApp, Inc
- # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = """
-
-module: na_ontap_lun_map
-
-short_description: NetApp ONTAP LUN maps
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Map and unmap LUNs on NetApp ONTAP.
-
-options:
-
- state:
- description:
- - Whether the specified LUN should exist or not.
- choices: ['present', 'absent']
- default: present
-
- initiator_group_name:
- description:
- - Initiator group to map to the given LUN.
- required: true
-
- path:
- description:
- - Path of the LUN..
- required: true
-
- vserver:
- required: true
- description:
- - The name of the vserver to use.
-
- lun_id:
- description:
- - LUN ID assigned for the map.
-
-
-"""
-
-EXAMPLES = """
-- name: Create LUN mapping
- na_ontap_lun_map:
- state: present
- initiator_group_name: ansibleIgroup3234
- path: /vol/iscsi_path/iscsi_lun
- vserver: ci_dev
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-- name: Unmap LUN
- na_ontap_lun_map:
- state: absent
- initiator_group_name: ansibleIgroup3234
- path: /vol/iscsi_path/iscsi_lun
- vserver: ci_dev
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-lun_node:
- description: NetApp controller that is hosting the LUN.
- returned: success
- type: str
- sample: node01
-lun_ostype:
- description: Specifies the OS of the host accessing the LUN.
- returned: success
- type: str
- sample: vmware
-lun_serial:
- description: A unique, 12-byte, ASCII string used to identify the LUN.
- returned: success
- type: str
- sample: 80E7/]LZp1Tt
-lun_naa_id:
- description: The Network Address Authority (NAA) identifier for the LUN.
- returned: success
- type: str
- sample: 600a0980383045372f5d4c5a70315474
-lun_state:
- description: Online or offline status of the LUN.
- returned: success
- type: str
- sample: online
-lun_size:
- description: Size of the LUN in bytes.
- returned: success
- type: int
- sample: 2199023255552
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-import codecs
-from ansible.module_utils._text import to_text, to_bytes
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapLUNMap(object):
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- initiator_group_name=dict(required=True, type='str'),
- path=dict(required=True, type='str'),
- vserver=dict(required=True, type='str'),
- lun_id=dict(required=False, type='str', default=None),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('state', 'present', ['path'])
- ],
- supports_check_mode=True
- )
-
- self.result = dict(
- changed=False,
- )
-
- p = self.module.params
-
- # set up state variables
- self.state = p['state']
- self.initiator_group_name = p['initiator_group_name']
- self.path = p['path']
- self.vserver = p['vserver']
- self.lun_id = p['lun_id']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver)
-
- def get_lun_map(self):
- """
- Return details about the LUN map
-
- :return: Details about the lun map
- :rtype: dict
- """
- lun_info = netapp_utils.zapi.NaElement('lun-map-list-info')
- lun_info.add_new_child('path', self.path)
- result = self.server.invoke_successfully(lun_info, True)
- return_value = None
- igroups = result.get_child_by_name('initiator-groups')
- if igroups:
- for igroup_info in igroups.get_children():
- initiator_group_name = igroup_info.get_child_content('initiator-group-name')
- lun_id = igroup_info.get_child_content('lun-id')
- if initiator_group_name == self.initiator_group_name:
- return_value = {
- 'lun_id': lun_id
- }
- break
-
- return return_value
-
- def get_lun(self):
- """
- Return details about the LUN
-
- :return: Details about the lun
- :rtype: dict
- """
- # build the lun query
- query_details = netapp_utils.zapi.NaElement('lun-info')
- query_details.add_new_child('path', self.path)
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
-
- lun_query = netapp_utils.zapi.NaElement('lun-get-iter')
- lun_query.add_child_elem(query)
-
- # find lun using query
- result = self.server.invoke_successfully(lun_query, True)
- return_value = None
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- lun = result.get_child_by_name('attributes-list').get_child_by_name('lun-info')
-
- # extract and assign lun information to return value
- hexlify = codecs.getencoder('hex')
- naa_hex = to_text(hexlify(to_bytes(lun.get_child_content('serial-number')))[0])
- return_value = {
- 'lun_node': lun.get_child_content('node'),
- 'lun_ostype': lun.get_child_content('multiprotocol-type'),
- 'lun_serial': lun.get_child_content('serial-number'),
- 'lun_naa_id': '600a0980' + naa_hex,
- 'lun_state': lun.get_child_content('state'),
- 'lun_size': lun.get_child_content('size'),
- }
-
- return return_value
-
- def create_lun_map(self):
- """
- Create LUN map
- """
- options = {'path': self.path, 'initiator-group': self.initiator_group_name}
- if self.lun_id is not None:
- options['lun-id'] = self.lun_id
- lun_map_create = netapp_utils.zapi.NaElement.create_node_with_children('lun-map', **options)
-
- try:
- self.server.invoke_successfully(lun_map_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error mapping lun %s of initiator_group_name %s: %s" %
- (self.path, self.initiator_group_name, to_native(e)),
- exception=traceback.format_exc())
-
- def delete_lun_map(self):
- """
- Unmap LUN map
- """
- lun_map_delete = netapp_utils.zapi.NaElement.create_node_with_children('lun-unmap', **{'path': self.path, 'initiator-group': self.initiator_group_name})
-
- try:
- self.server.invoke_successfully(lun_map_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg="Error unmapping lun %s of initiator_group_name %s: %s" %
- (self.path, self.initiator_group_name, to_native(e)),
- exception=traceback.format_exc())
-
- def apply(self):
- netapp_utils.ems_log_event("na_ontap_lun_map", self.server)
- lun_details = self.get_lun()
- lun_map_details = self.get_lun_map()
-
- if self.state == 'present' and lun_details:
- self.result.update(lun_details)
-
- if self.state == 'present' and not lun_map_details:
- self.result['changed'] = True
- if not self.module.check_mode:
- self.create_lun_map()
- elif self.state == 'absent' and lun_map_details:
- self.result['changed'] = True
- if not self.module.check_mode:
- self.delete_lun_map()
-
- self.module.exit_json(**self.result)
-
-
-def main():
- v = NetAppOntapLUNMap()
- v.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_motd.py b/lib/ansible/modules/storage/netapp/na_ontap_motd.py
deleted file mode 100644
index 7f48ebcb8d..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_motd.py
+++ /dev/null
@@ -1,209 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# (c) 2018 Piotr Olczak <piotr.olczak@redhat.com>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-module: na_ontap_motd
-author:
- - Piotr Olczak (@dprts) <polczak@redhat.com>
- - NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-extends_documentation_fragment:
- - netapp.na_ontap
-short_description: Setup motd
-description:
- - This module allows you to manipulate motd for a vserver
- - It also allows to manipulate motd at the cluster level by using the cluster vserver (cserver)
-version_added: "2.7"
-requirements:
- - netapp_lib
-options:
- state:
- description:
- - If C(state=present) sets MOTD given in I(message) C(state=absent) removes it.
- choices: ['present', 'absent']
- default: present
- message:
- description:
- - MOTD Text message, required when C(state=present).
- type: str
- vserver:
- description:
- - The name of the SVM motd should be set for.
- required: true
- type: str
- show_cluster_motd:
- description:
- - Set to I(false) if Cluster-level Message of the Day should not be shown
- type: bool
- default: True
-
-'''
-
-EXAMPLES = '''
-
-- name: Set Cluster-Level MOTD
- na_ontap_motd:
- vserver: my_ontap_cluster
- message: "Cluster wide MOTD"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- state: present
- https: true
-
-- name: Set MOTD for I(rhev_nfs_krb) SVM, do not show Cluster-Level MOTD
- na_ontap_motd:
- vserver: rhev_nfs_krb
- message: "Access to rhev_nfs_krb is also restricted"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- state: present
- show_cluster_motd: False
- https: true
-
-- name: Remove Cluster-Level MOTD
- na_ontap_motd:
- vserver: my_ontap_cluster
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- state: absent
- https: true
-
-'''
-
-RETURN = '''
-
-'''
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPMotd(object):
-
- def __init__(self):
- argument_spec = netapp_utils.na_ontap_host_argument_spec()
- argument_spec.update(dict(
- state=dict(required=False, default='present', choices=['present', 'absent']),
- vserver=dict(required=True, type='str'),
- message=dict(default='', type='str'),
- show_cluster_motd=dict(default=True, type='bool')
- ))
-
- self.module = AnsibleModule(
- argument_spec=argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
-
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def motd_get_iter(self):
- """
- Compose NaElement object to query current motd
- :return: NaElement object for vserver-motd-get-iter
- """
- motd_get_iter = netapp_utils.zapi.NaElement('vserver-motd-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- motd_info = netapp_utils.zapi.NaElement('vserver-motd-info')
- motd_info.add_new_child('is-cluster-message-enabled', str(self.parameters['show_cluster_motd']))
- motd_info.add_new_child('vserver', self.parameters['vserver'])
- query.add_child_elem(motd_info)
- motd_get_iter.add_child_elem(query)
- return motd_get_iter
-
- def motd_get(self):
- """
- Get current motd
- :return: Dictionary of current motd details if query successful, else None
- """
- motd_get_iter = self.motd_get_iter()
- motd_result = dict()
- try:
- result = self.server.invoke_successfully(motd_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching motd info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) > 0:
- motd_info = result.get_child_by_name('attributes-list').get_child_by_name(
- 'vserver-motd-info')
- motd_result['message'] = motd_info.get_child_content('message')
- motd_result['message'] = str(motd_result['message']).rstrip()
- motd_result['show_cluster_motd'] = True if motd_info.get_child_content(
- 'is-cluster-message-enabled') == 'true' else False
- motd_result['vserver'] = motd_info.get_child_content('vserver')
- return motd_result
- return None
-
- def modify_motd(self):
- motd_create = netapp_utils.zapi.NaElement('vserver-motd-modify-iter')
- motd_create.add_new_child('message', self.parameters['message'])
- motd_create.add_new_child(
- 'is-cluster-message-enabled', 'true' if self.parameters['show_cluster_motd'] is True else 'false')
- query = netapp_utils.zapi.NaElement('query')
- motd_info = netapp_utils.zapi.NaElement('vserver-motd-info')
- motd_info.add_new_child('vserver', self.parameters['vserver'])
- query.add_child_elem(motd_info)
- motd_create.add_child_elem(query)
- try:
- self.server.invoke_successfully(motd_create, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as err:
- self.module.fail_json(msg="Error creating motd: %s" % (to_native(err)), exception=traceback.format_exc())
- return motd_create
-
- def apply(self):
- """
- Applies action from playbook
- """
- netapp_utils.ems_log_event("na_ontap_motd", self.server)
- current = self.motd_get()
- if self.parameters['state'] == 'present' and self.parameters['message'] == "":
- self.module.fail_json(msg="message parameter cannot be empty")
- if self.parameters['state'] == 'absent':
- # Just make sure it is empty
- self.parameters['message'] = ''
- if current['message'] == 'None':
- current = None
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action is None and self.parameters['state'] == 'present':
- self.na_helper.get_modified_attributes(current, self.parameters)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- self.modify_motd()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- motd_obj = NetAppONTAPMotd()
- motd_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_ndmp.py b/lib/ansible/modules/storage/netapp/na_ontap_ndmp.py
deleted file mode 100644
index 53e03ee861..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_ndmp.py
+++ /dev/null
@@ -1,342 +0,0 @@
-#!/usr/bin/python
-""" this is ndmp module
-
- (c) 2019, NetApp, Inc
- # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-"""
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'
-}
-
-
-DOCUMENTATION = '''
----
-module: na_ontap_ndmp
-short_description: NetApp ONTAP NDMP services configuration
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - Modify NDMP Services.
-
-options:
-
- vserver:
- description:
- - Name of the vserver.
- required: true
- type: str
-
- abort_on_disk_error:
- description:
- - Enable abort on disk error.
- type: bool
-
- authtype:
- description:
- - Authentication type.
- type: list
-
- backup_log_enable:
- description:
- - Enable backup log.
- type: bool
-
- data_port_range:
- description:
- - Data port range.
- type: str
-
- debug_enable:
- description:
- - Enable debug.
- type: bool
-
- debug_filter:
- description:
- - Debug filter.
- type: str
-
- dump_detailed_stats:
- description:
- - Enable logging of VM stats for dump.
- type: bool
-
- dump_logical_find:
- description:
- - Enable logical find for dump.
- type: str
-
- enable:
- description:
- - Enable NDMP on vserver.
- type: bool
-
- fh_dir_retry_interval:
- description:
- - FH throttle value for dir.
- type: int
-
- fh_node_retry_interval:
- description:
- - FH throttle value for node.
- type: int
-
- ignore_ctime_enabled:
- description:
- - Ignore ctime.
- type: bool
-
- is_secure_control_connection_enabled:
- description:
- - Is secure control connection enabled.
- type: bool
-
- offset_map_enable:
- description:
- - Enable offset map.
- type: bool
-
- per_qtree_exclude_enable:
- description:
- - Enable per qtree exclusion.
- type: bool
-
- preferred_interface_role:
- description:
- - Preferred interface role.
- type: list
-
- restore_vm_cache_size:
- description:
- - Restore VM file cache size.
- type: int
-
- secondary_debug_filter:
- description:
- - Secondary debug filter.
- type: str
-
- tcpnodelay:
- description:
- - Enable TCP nodelay.
- type: bool
-
- tcpwinsize:
- description:
- - TCP window size.
- type: int
-'''
-
-EXAMPLES = '''
- - name: modify ndmp
- na_ontap_ndmp:
- vserver: ansible
- hostname: "{{ hostname }}"
- abort_on_disk_error: true
- authtype: plaintext,challenge
- backup_log_enable: true
- data_port_range: 8000-9000
- debug_enable: true
- debug_filter: filter
- dump_detailed_stats: true
- dump_logical_find: default
- enable: true
- fh_dir_retry_interval: 100
- fh_node_retry_interval: 100
- ignore_ctime_enabled: true
- is_secure_control_connection_enabled: true
- offset_map_enable: true
- per_qtree_exclude_enable: true
- preferred_interface_role: node_mgmt,intercluster
- restore_vm_cache_size: 1000
- secondary_debug_filter: filter
- tcpnodelay: true
- tcpwinsize: 10000
- username: user
- password: pass
- https: False
-'''
-
-RETURN = '''
-'''
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPNdmp(object):
- '''
- modify vserver cifs security
- '''
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.modifiable_options = dict(
- abort_on_disk_error=dict(required=False, type='bool'),
- authtype=dict(required=False, type='list'),
- backup_log_enable=dict(required=False, type='bool'),
- data_port_range=dict(required=False, type='str'),
- debug_enable=dict(required=False, type='bool'),
- debug_filter=dict(required=False, type='str'),
- dump_detailed_stats=dict(required=False, type='bool'),
- dump_logical_find=dict(required=False, type='str'),
- enable=dict(required=False, type='bool'),
- fh_dir_retry_interval=dict(required=False, type='int'),
- fh_node_retry_interval=dict(required=False, type='int'),
- ignore_ctime_enabled=dict(required=False, type='bool'),
- is_secure_control_connection_enabled=dict(required=False, type='bool'),
- offset_map_enable=dict(required=False, type='bool'),
- per_qtree_exclude_enable=dict(required=False, type='bool'),
- preferred_interface_role=dict(required=False, type='list'),
- restore_vm_cache_size=dict(required=False, type='int'),
- secondary_debug_filter=dict(required=False, type='str'),
- tcpnodelay=dict(required=False, type='bool'),
- tcpwinsize=dict(required=False, type='int')
- )
- self.argument_spec.update(dict(
- vserver=dict(required=True, type='str')
- ))
-
- self.argument_spec.update(self.modifiable_options)
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def ndmp_get_iter(self):
- """
- get current vserver ndmp attributes.
- :return: a dict of ndmp attributes.
- """
- ndmp_get = netapp_utils.zapi.NaElement('ndmp-vserver-attributes-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- ndmp_info = netapp_utils.zapi.NaElement('ndmp-vserver-attributes-info')
- ndmp_info.add_new_child('vserver', self.parameters['vserver'])
- query.add_child_elem(ndmp_info)
- ndmp_get.add_child_elem(query)
- ndmp_details = dict()
- try:
- result = self.server.invoke_successfully(ndmp_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching ndmp from %s: %s'
- % (self.parameters['vserver'], to_native(error)),
- exception=traceback.format_exc())
-
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) > 0:
- ndmp_attributes = result.get_child_by_name('attributes-list').get_child_by_name('ndmp-vserver-attributes-info')
- self.get_ndmp_details(ndmp_details, ndmp_attributes)
- return ndmp_details
-
- def get_ndmp_details(self, ndmp_details, ndmp_attributes):
- """
- :param ndmp_details: a dict of current ndmp.
- :param ndmp_attributes: ndmp returned from api call in xml format.
- :return: None
- """
- for option in self.modifiable_options.keys():
- option_type = self.modifiable_options[option]['type']
- if option_type == 'bool':
- ndmp_details[option] = self.str_to_bool(ndmp_attributes.get_child_content(self.attribute_to_name(option)))
- elif option_type == 'int':
- ndmp_details[option] = int(ndmp_attributes.get_child_content(self.attribute_to_name(option)))
- elif option_type == 'list':
- child_list = ndmp_attributes.get_child_by_name(self.attribute_to_name(option))
- values = [child.get_content() for child in child_list.get_children()]
- ndmp_details[option] = values
- else:
- ndmp_details[option] = ndmp_attributes.get_child_content(self.attribute_to_name(option))
-
- def modify_ndmp(self, modify):
- """
- :param modify: A list of attributes to modify
- :return: None
- """
- ndmp_modify = netapp_utils.zapi.NaElement('ndmp-vserver-attributes-modify')
- for attribute in modify:
- if attribute == 'authtype':
- authtypes = netapp_utils.zapi.NaElement('authtype')
- types = self.parameters['authtype']
- for authtype in types:
- authtypes.add_new_child('ndmpd-authtypes', authtype)
- ndmp_modify.add_child_elem(authtypes)
- elif attribute == 'preferred_interface_role':
- preferred_interface_roles = netapp_utils.zapi.NaElement('preferred-interface-role')
- roles = self.parameters['preferred_interface_role']
- for role in roles:
- preferred_interface_roles.add_new_child('netport-role', role)
- ndmp_modify.add_child_elem(preferred_interface_roles)
- else:
- ndmp_modify.add_new_child(self.attribute_to_name(attribute), str(self.parameters[attribute]))
- try:
- self.server.invoke_successfully(ndmp_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error modifying ndmp on %s: %s'
- % (self.parameters['vserver'], to_native(e)),
- exception=traceback.format_exc())
-
- @staticmethod
- def attribute_to_name(attribute):
- return str.replace(attribute, '_', '-')
-
- @staticmethod
- def str_to_bool(s):
- if s == 'true':
- return True
- else:
- return False
-
- def apply(self):
- """Call modify operations."""
- self.asup_log_for_cserver("na_ontap_ndmp")
- current = self.ndmp_get_iter()
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if modify:
- self.modify_ndmp(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
-
-def main():
- obj = NetAppONTAPNdmp()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_net_ifgrp.py b/lib/ansible/modules/storage/netapp/na_ontap_net_ifgrp.py
deleted file mode 100644
index afc22151a3..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_net_ifgrp.py
+++ /dev/null
@@ -1,307 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = """
-module: na_ontap_net_ifgrp
-short_description: NetApp Ontap modify network interface group
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create, modify ports, destroy the network interface group
-options:
- state:
- description:
- - Whether the specified network interface group should exist or not.
- choices: ['present', 'absent']
- default: present
-
- distribution_function:
- description:
- - Specifies the traffic distribution function for the ifgrp.
- choices: ['mac', 'ip', 'sequential', 'port']
-
- name:
- description:
- - Specifies the interface group name.
- required: true
-
- mode:
- description:
- - Specifies the link policy for the ifgrp.
-
- node:
- description:
- - Specifies the name of node.
- required: true
-
- ports:
- aliases:
- - port
- description:
- - List of expected ports to be present in the interface group.
- - If a port is present in this list, but not on the target, it will be added.
- - If a port is not in the list, but present on the target, it will be removed.
- - Make sure the list contains all ports you want to see on the target.
- version_added: '2.8'
-"""
-
-EXAMPLES = """
- - name: create ifgrp
- na_ontap_net_ifgrp:
- state: present
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- distribution_function: ip
- name: a0c
- ports: [e0a]
- mode: multimode
- node: "{{ Vsim node name }}"
- - name: modify ports in an ifgrp
- na_ontap_net_ifgrp:
- state: present
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- distribution_function: ip
- name: a0c
- port: [e0a, e0c]
- mode: multimode
- node: "{{ Vsim node name }}"
- - name: delete ifgrp
- na_ontap_net_ifgrp:
- state: absent
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- name: a0c
- node: "{{ Vsim node name }}"
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapIfGrp(object):
- """
- Create, Modifies and Destroys a IfGrp
- """
- def __init__(self):
- """
- Initialize the Ontap IfGrp class
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- distribution_function=dict(required=False, type='str', choices=['mac', 'ip', 'sequential', 'port']),
- name=dict(required=True, type='str'),
- mode=dict(required=False, type='str'),
- node=dict(required=True, type='str'),
- ports=dict(required=False, type='list', aliases=["port"]),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('state', 'present', ['distribution_function', 'mode'])
- ],
- supports_check_mode=True
- )
-
- # set up variables
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- return
-
- def get_if_grp(self):
- """
- Return details about the if_group
- :param:
- name : Name of the if_group
-
- :return: Details about the if_group. None if not found.
- :rtype: dict
- """
- if_group_iter = netapp_utils.zapi.NaElement('net-port-get-iter')
- if_group_info = netapp_utils.zapi.NaElement('net-port-info')
- if_group_info.add_new_child('port', self.parameters['name'])
- if_group_info.add_new_child('port-type', 'if_group')
- if_group_info.add_new_child('node', self.parameters['node'])
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(if_group_info)
- if_group_iter.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(if_group_iter, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting if_group %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- return_value = None
-
- if result.get_child_by_name('num-records') and int(result['num-records']) >= 1:
- if_group_attributes = result['attributes-list']['net-port-info']
- return_value = {
- 'name': if_group_attributes['port'],
- 'distribution_function': if_group_attributes['ifgrp-distribution-function'],
- 'mode': if_group_attributes['ifgrp-mode'],
- 'node': if_group_attributes['node'],
- }
-
- return return_value
-
- def get_if_grp_ports(self):
- """
- Return ports of the if_group
- :param:
- name : Name of the if_group
- :return: Ports of the if_group. None if not found.
- :rtype: dict
- """
- if_group_iter = netapp_utils.zapi.NaElement('net-port-ifgrp-get')
- if_group_iter.add_new_child('ifgrp-name', self.parameters['name'])
- if_group_iter.add_new_child('node', self.parameters['node'])
- try:
- result = self.server.invoke_successfully(if_group_iter, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting if_group ports %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- port_list = []
- if result.get_child_by_name('attributes'):
- if_group_attributes = result['attributes']['net-ifgrp-info']
- if if_group_attributes.get_child_by_name('ports'):
- ports = if_group_attributes.get_child_by_name('ports').get_children()
- for each in ports:
- port_list.append(each.get_content())
- return {'ports': port_list}
-
- def create_if_grp(self):
- """
- Creates a new ifgrp
- """
- route_obj = netapp_utils.zapi.NaElement("net-port-ifgrp-create")
- route_obj.add_new_child("distribution-function", self.parameters['distribution_function'])
- route_obj.add_new_child("ifgrp-name", self.parameters['name'])
- route_obj.add_new_child("mode", self.parameters['mode'])
- route_obj.add_new_child("node", self.parameters['node'])
- try:
- self.server.invoke_successfully(route_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating if_group %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- for port in self.parameters.get('ports'):
- self.add_port_to_if_grp(port)
-
- def delete_if_grp(self):
- """
- Deletes a ifgrp
- """
- route_obj = netapp_utils.zapi.NaElement("net-port-ifgrp-destroy")
- route_obj.add_new_child("ifgrp-name", self.parameters['name'])
- route_obj.add_new_child("node", self.parameters['node'])
- try:
- self.server.invoke_successfully(route_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting if_group %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def add_port_to_if_grp(self, port):
- """
- adds port to a ifgrp
- """
- route_obj = netapp_utils.zapi.NaElement("net-port-ifgrp-add-port")
- route_obj.add_new_child("ifgrp-name", self.parameters['name'])
- route_obj.add_new_child("port", port)
- route_obj.add_new_child("node", self.parameters['node'])
- try:
- self.server.invoke_successfully(route_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error adding port %s to if_group %s: %s' %
- (port, self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_ports(self, current_ports):
- add_ports = set(self.parameters['ports']) - set(current_ports)
- remove_ports = set(current_ports) - set(self.parameters['ports'])
- for port in add_ports:
- self.add_port_to_if_grp(port)
- for port in remove_ports:
- self.remove_port_to_if_grp(port)
-
- def remove_port_to_if_grp(self, port):
- """
- removes port from a ifgrp
- """
- route_obj = netapp_utils.zapi.NaElement("net-port-ifgrp-remove-port")
- route_obj.add_new_child("ifgrp-name", self.parameters['name'])
- route_obj.add_new_child("port", port)
- route_obj.add_new_child("node", self.parameters['node'])
- try:
- self.server.invoke_successfully(route_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error removing port %s to if_group %s: %s' %
- (port, self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_net_ifgrp", cserver)
-
- def apply(self):
- self.autosupport_log()
- current, modify = self.get_if_grp(), None
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action is None and self.parameters['state'] == 'present':
- current_ports = self.get_if_grp_ports()
- modify = self.na_helper.get_modified_attributes(current_ports, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_if_grp()
- elif cd_action == 'delete':
- self.delete_if_grp()
- elif modify:
- self.modify_ports(current_ports['ports'])
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Creates the NetApp Ontap Net Route object and runs the correct play task
- """
- obj = NetAppOntapIfGrp()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_net_port.py b/lib/ansible/modules/storage/netapp/na_ontap_net_port.py
deleted file mode 100644
index a1631d4bdb..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_net_port.py
+++ /dev/null
@@ -1,226 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = """
-module: na_ontap_net_port
-short_description: NetApp ONTAP network ports.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Modify a ONTAP network port.
-options:
- state:
- description:
- - Whether the specified net port should exist or not.
- choices: ['present']
- default: present
- node:
- description:
- - Specifies the name of node.
- required: true
- ports:
- aliases:
- - port
- description:
- - Specifies the name of port(s).
- required: true
- mtu:
- description:
- - Specifies the maximum transmission unit (MTU) reported by the port.
- autonegotiate_admin:
- description:
- - Enables or disables Ethernet auto-negotiation of speed,
- duplex and flow control.
- duplex_admin:
- description:
- - Specifies the user preferred duplex setting of the port.
- - Valid values auto, half, full
- speed_admin:
- description:
- - Specifies the user preferred speed setting of the port.
- flowcontrol_admin:
- description:
- - Specifies the user preferred flow control setting of the port.
- ipspace:
- description:
- - Specifies the port's associated IPspace name.
- - The 'Cluster' ipspace is reserved for cluster ports.
-"""
-
-EXAMPLES = """
- - name: Modify Net Port
- na_ontap_net_port:
- state: present
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- node: "{{ node_name }}"
- ports: e0d,e0c
- autonegotiate_admin: true
-"""
-
-RETURN = """
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapNetPort(object):
- """
- Modify a Net port
- """
-
- def __init__(self):
- """
- Initialize the Ontap Net Port Class
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present'], default='present'),
- node=dict(required=True, type="str"),
- ports=dict(required=True, type="list", aliases=['port']),
- mtu=dict(required=False, type="str", default=None),
- autonegotiate_admin=dict(required=False, type="str", default=None),
- duplex_admin=dict(required=False, type="str", default=None),
- speed_admin=dict(required=False, type="str", default=None),
- flowcontrol_admin=dict(required=False, type="str", default=None),
- ipspace=dict(required=False, type="str", default=None),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- self.set_playbook_zapi_key_map()
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- return
-
- def set_playbook_zapi_key_map(self):
- self.na_helper.zapi_string_keys = {
- 'mtu': 'mtu',
- 'autonegotiate_admin': 'is-administrative-auto-negotiate',
- 'duplex_admin': 'administrative-duplex',
- 'speed_admin': 'administrative-speed',
- 'flowcontrol_admin': 'administrative-flowcontrol',
- 'ipspace': 'ipspace'
- }
-
- def get_net_port(self, port):
- """
- Return details about the net port
- :param: port: Name of the port
- :return: Dictionary with current state of the port. None if not found.
- :rtype: dict
- """
- net_port_get = netapp_utils.zapi.NaElement('net-port-get-iter')
- attributes = {
- 'query': {
- 'net-port-info': {
- 'node': self.parameters['node'],
- 'port': port
- }
- }
- }
- net_port_get.translate_struct(attributes)
-
- try:
- result = self.server.invoke_successfully(net_port_get, True)
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- port_info = result['attributes-list']['net-port-info']
- port_details = dict()
- else:
- return None
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting net ports for %s: %s' % (self.parameters['node'], to_native(error)),
- exception=traceback.format_exc())
-
- for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
- port_details[item_key] = port_info.get_child_content(zapi_key)
- return port_details
-
- def modify_net_port(self, port, modify):
- """
- Modify a port
-
- :param port: Name of the port
- :param modify: dict with attributes to be modified
- :return: None
- """
- port_modify = netapp_utils.zapi.NaElement('net-port-modify')
- port_attributes = {'node': self.parameters['node'],
- 'port': port}
- for key in modify:
- if key in self.na_helper.zapi_string_keys:
- zapi_key = self.na_helper.zapi_string_keys.get(key)
- port_attributes[zapi_key] = modify[key]
- port_modify.translate_struct(port_attributes)
- try:
- self.server.invoke_successfully(port_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying net ports for %s: %s' % (self.parameters['node'], to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- """
- AutoSupport log for na_ontap_net_port
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_net_port", cserver)
-
- def apply(self):
- """
- Run Module based on play book
- """
-
- self.autosupport_log()
- # Run the task for all ports in the list of 'ports'
- for port in self.parameters['ports']:
- current = self.get_net_port(port)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if modify:
- self.modify_net_port(port, modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Create the NetApp Ontap Net Port Object and modify it
- """
- obj = NetAppOntapNetPort()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_net_routes.py b/lib/ansible/modules/storage/netapp/na_ontap_net_routes.py
deleted file mode 100644
index 76ccb62e49..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_net_routes.py
+++ /dev/null
@@ -1,324 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_net_routes
-short_description: NetApp ONTAP network routes
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Modify ONTAP network routes.
-options:
- state:
- description:
- - Whether you want to create or delete a network route.
- choices: ['present', 'absent']
- default: present
- vserver:
- description:
- - The name of the vserver.
- required: true
- destination:
- description:
- - Specify the route destination.
- - Example 10.7.125.5/20, fd20:13::/64.
- required: true
- gateway:
- description:
- - Specify the route gateway.
- - Example 10.7.125.1, fd20:13::1.
- required: true
- metric:
- description:
- - Specify the route metric.
- - If this field is not provided the default will be set to 20.
- from_destination:
- description:
- - Specify the route destination that should be changed.
- - new_destination was removed to fix idempotency issues. To rename destination the original goes to from_destination and the new goes to destination.
- version_added: '2.8'
- from_gateway:
- description:
- - Specify the route gateway that should be changed.
- version_added: '2.8'
- from_metric:
- description:
- - Specify the route metric that should be changed.
- version_added: '2.8'
-'''
-
-EXAMPLES = """
- - name: create route
- na_ontap_net_routes:
- state: present
- vserver: "{{ Vserver name }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- destination: 10.7.125.5/20
- gateway: 10.7.125.1
- metric: 30
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapNetRoutes(object):
- """
- Create, Modifies and Destroys a Net Route
- """
-
- def __init__(self):
- """
- Initialize the Ontap Net Route class
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- destination=dict(required=True, type='str'),
- gateway=dict(required=True, type='str'),
- metric=dict(required=False, type='str'),
- from_destination=dict(required=False, type='str', default=None),
- from_gateway=dict(required=False, type='str', default=None),
- from_metric=dict(required=False, type='str', default=None),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
- return
-
- def create_net_route(self, current_metric=None):
- """
- Creates a new Route
- """
- route_obj = netapp_utils.zapi.NaElement('net-routes-create')
- route_obj.add_new_child("destination", self.parameters['destination'])
- route_obj.add_new_child("gateway", self.parameters['gateway'])
- if current_metric is None and self.parameters.get('metric') is not None:
- metric = self.parameters['metric']
- else:
- metric = current_metric
- # Metric can be None, Can't set metric to none
- if metric is not None:
- route_obj.add_new_child("metric", metric)
- try:
- self.server.invoke_successfully(route_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating net route: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def delete_net_route(self, params=None):
- """
- Deletes a given Route
- """
- route_obj = netapp_utils.zapi.NaElement('net-routes-destroy')
- if params is None:
- params = self.parameters
- route_obj.add_new_child("destination", params['destination'])
- route_obj.add_new_child("gateway", params['gateway'])
- try:
- self.server.invoke_successfully(route_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting net route: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def modify_net_route(self, current, desired):
- """
- Modify a net route
- """
- # return if there is nothing to change
- for key, val in desired.items():
- if val != current[key]:
- self.na_helper.changed = True
- break
- if not self.na_helper.changed:
- return
- # delete and re-create with new params
- self.delete_net_route(current)
- route_obj = netapp_utils.zapi.NaElement('net-routes-create')
- for attribute in ['metric', 'destination', 'gateway']:
- if desired.get(attribute) is not None:
- value = desired[attribute]
- else:
- value = current[attribute]
- route_obj.add_new_child(attribute, value)
- try:
- result = self.server.invoke_successfully(route_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- # restore the old route, create the route with the existing metric
- self.create_net_route(current['metric'])
- # return if desired route already exists
- if to_native(error.code) == '13001':
- return
- # Invalid value specified for any of the attributes
- self.module.fail_json(msg='Error modifying net route: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def get_net_route(self, params=None):
- """
- Checks to see if a route exist or not
- :return: NaElement object if a route exists, None otherwise
- """
- if params is not None:
- # we need at least on of the new_destination or new_gateway to fetch desired route
- if params.get('destination') is None and params.get('gateway') is None:
- return None
- current = None
- route_obj = netapp_utils.zapi.NaElement('net-routes-get')
- for attr in ['destination', 'gateway']:
- if params and params.get(attr) is not None:
- value = params[attr]
- else:
- value = self.parameters[attr]
- route_obj.add_new_child(attr, value)
- try:
- result = self.server.invoke_successfully(route_obj, True)
- if result.get_child_by_name('attributes') is not None:
- route_info = result.get_child_by_name('attributes').get_child_by_name('net-vs-routes-info')
- current = {
- 'destination': route_info.get_child_content('destination'),
- 'gateway': route_info.get_child_content('gateway'),
- 'metric': route_info.get_child_content('metric')
- }
-
- except netapp_utils.zapi.NaApiError as error:
- # Error 13040 denotes a route doesn't exist.
- if to_native(error.code) == "15661":
- return None
- self.module.fail_json(msg='Error fetching net route: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
- return current
-
- def is_modify_action(self, current, desired):
- """
- Get desired action to be applied for net routes
- Destination and gateway are unique params for a route and cannot be duplicated
- So if a route with desired destination or gateway exists already, we don't try to modify
- :param current: current details
- :param desired: desired details
- :return: create / delete / modify / None
- """
- if current is None and desired is None:
- # this is invalid
- # cannot modify a non existent resource
- return None
- if current is None and desired is not None:
- # idempotency or duplication
- # we need not create
- return False
- if current is not None and desired is not None:
- # we can't modify an ambiguous route (idempotency/duplication)
- return False
- return True
-
- def get_params_to_be_modified(self, current):
- """
- Get parameters and values that need to be modified
- :param current: current details
- :return: dict(), None
- """
- if current is None:
- return None
- desired = dict()
- if self.parameters.get('new_destination') is not None and \
- self.parameters['new_destination'] != current['destination']:
- desired['destination'] = self.parameters['new_destination']
- if self.parameters.get('new_gateway') is not None and \
- self.parameters['new_gateway'] != current['gateway']:
- desired['gateway'] = self.parameters['new_gateway']
- if self.parameters.get('new_metric') is not None and \
- self.parameters['new_metric'] != current['metric']:
- desired['metric'] = self.parameters['new_metric']
- return desired
-
- def apply(self):
- """
- Run Module based on play book
- """
- netapp_utils.ems_log_event("na_ontap_net_routes", self.server)
- current = self.get_net_route()
- modify, cd_action = None, None
- modify_params = {'destination': self.parameters.get('from_destination'),
- 'gateway': self.parameters.get('from_gateway'),
- 'metric': self.parameters.get('from_metric')}
- # if any from_* param is present in playbook, check for modify action
- if any(modify_params.values()):
- # destination and gateway combination is unique, and is considered like a id. so modify destination
- # or gateway is considered a rename action. metric is considered an attribute of the route so it is
- # considered as modify.
- if modify_params.get('metric') is not None:
- modify = True
- old_params = current
- else:
- # get parameters that are eligible for modify
- old_params = self.get_net_route(modify_params)
- modify = self.na_helper.is_rename_action(old_params, current)
- if modify is None:
- self.module.fail_json(msg="Error modifying: route %s does not exist" % self.parameters['from_destination'])
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
-
- if cd_action == 'create':
- self.create_net_route()
- elif cd_action == 'delete':
- self.delete_net_route()
- elif modify:
- desired = {}
- for key, value in old_params.items():
- desired[key] = value
- for key, value in modify_params.items():
- if value is not None:
- desired[key] = self.parameters.get(key)
- self.modify_net_route(old_params, desired)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Creates the NetApp Ontap Net Route object and runs the correct play task
- """
- obj = NetAppOntapNetRoutes()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_net_subnet.py b/lib/ansible/modules/storage/netapp/na_ontap_net_subnet.py
deleted file mode 100644
index 96b50f7905..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_net_subnet.py
+++ /dev/null
@@ -1,326 +0,0 @@
-#!/usr/bin/python
-
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = """
-module: na_ontap_net_subnet
-short_description: NetApp ONTAP Create, delete, modify network subnets.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: Storage Engineering (@Albinpopote) <ansible@black-perl.fr>
-description:
-- Create, modify, destroy the network subnet
-options:
- state:
- description:
- - Whether the specified network interface group should exist or not.
- choices: ['present', 'absent']
- default: present
-
- broadcast_domain:
- description:
- - Specify the required broadcast_domain name for the subnet.
- - A broadcast domain can not be modified after the subnet has been created
- required: true
-
- name:
- description:
- - Specify the subnet name.
- required: true
-
- from_name:
- description:
- - Name of the subnet to be renamed
-
- gateway:
- description:
- - Specify the gateway for the default route of the subnet.
-
- ipspace:
- description:
- - Specify the ipspace for the subnet.
- - The default value for this parameter is the default IPspace, named 'Default'.
-
- ip_ranges:
- description:
- - Specify the list of IP address ranges associated with the subnet.
-
- subnet:
- description:
- - Specify the subnet (ip and mask).
- required: true
-"""
-
-EXAMPLES = """
- - name: create subnet
- na_ontap_net_subnet:
- state: present
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- subnet: 10.10.10.0/24
- name: subnet-adm
- ip_ranges: [ '10.10.10.30-10.10.10.40', '10.10.10.51' ]
- gateway: 10.10.10.254
- ipspace: Default
- broadcast_domain: Default
- - name: delete subnet
- na_ontap_net_subnet:
- state: absent
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- name: subnet-adm
- ipspace: Default
- - name: rename subnet
- na_ontap_net_subnet:
- state: present
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- name: subnet-adm-new
- from_name: subnet-adm
- ipspace: Default
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapSubnet(object):
- """
- Create, Modifies and Destroys a subnet
- """
- def __init__(self):
- """
- Initialize the ONTAP Subnet class
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- from_name=dict(required=False, type='str'),
- broadcast_domain=dict(required=False, type='str'),
- gateway=dict(required=False, type='str'),
- ip_ranges=dict(required=False, type=list),
- ipspace=dict(required=False, type='str'),
- subnet=dict(required=False, type='str')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- return
-
- def get_subnet(self, name=None):
- """
- Return details about the subnet
- :param:
- name : Name of the subnet
- :return: Details about the subnet. None if not found.
- :rtype: dict
- """
- if name is None:
- name = self.parameters.get('name')
-
- subnet_iter = netapp_utils.zapi.NaElement('net-subnet-get-iter')
- subnet_info = netapp_utils.zapi.NaElement('net-subnet-info')
- subnet_info.add_new_child('subnet-name', name)
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(subnet_info)
-
- subnet_iter.add_child_elem(query)
-
- result = self.server.invoke_successfully(subnet_iter, True)
-
- return_value = None
- # check if query returns the expected subnet
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
-
- subnet_attributes = result.get_child_by_name('attributes-list').get_child_by_name('net-subnet-info')
- broadcast_domain = subnet_attributes.get_child_content('broadcast-domain')
- gateway = subnet_attributes.get_child_content('gateway')
- ipspace = subnet_attributes.get_child_content('ipspace')
- subnet = subnet_attributes.get_child_content('subnet')
- name = subnet_attributes.get_child_content('subnet-name')
-
- ip_ranges = []
- range_obj = subnet_attributes.get_child_by_name('ip-ranges').get_children()
- for elem in range_obj:
- ip_ranges.append(elem.get_content())
-
- return_value = {
- 'name': name,
- 'broadcast_domain': broadcast_domain,
- 'gateway': gateway,
- 'ip_ranges': ip_ranges,
- 'ipspace': ipspace,
- 'subnet': subnet
- }
-
- return return_value
-
- def create_subnet(self):
- """
- Creates a new subnet
- """
- options = {'subnet-name': self.parameters.get('name'),
- 'broadcast-domain': self.parameters.get('broadcast_domain'),
- 'subnet': self.parameters.get('subnet')}
- subnet_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'net-subnet-create', **options)
-
- if self.parameters.get('gateway'):
- subnet_create.add_new_child('gateway', self.parameters.get('gateway'))
- if self.parameters.get('ip_ranges'):
- subnet_ips = netapp_utils.zapi.NaElement('ip-ranges')
- subnet_create.add_child_elem(subnet_ips)
- for ip_range in self.parameters.get('ip_ranges'):
- subnet_ips.add_new_child('ip-range', ip_range)
- if self.parameters.get('ipspace'):
- subnet_create.add_new_child('ipspace', self.parameters.get('ipspace'))
-
- try:
- self.server.invoke_successfully(subnet_create, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating subnet %s: %s' % (self.parameters.get('name'), to_native(error)),
- exception=traceback.format_exc())
-
- def delete_subnet(self):
- """
- Deletes a subnet
- """
- subnet_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'net-subnet-destroy', **{'subnet-name': self.parameters.get('name')})
-
- try:
- self.server.invoke_successfully(subnet_delete, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting subnet %s: %s' % (self.parameters.get('name'), to_native(error)),
- exception=traceback.format_exc())
-
- def modify_subnet(self):
- """
- Modifies a subnet
- """
- options = {'subnet-name': self.parameters.get('name')}
-
- subnet_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'net-subnet-modify', **options)
-
- if self.parameters.get('gateway'):
- subnet_modify.add_new_child('gateway', self.parameters.get('gateway'))
- if self.parameters.get('ip_ranges'):
- subnet_ips = netapp_utils.zapi.NaElement('ip-ranges')
- subnet_modify.add_child_elem(subnet_ips)
- for ip_range in self.parameters.get('ip_ranges'):
- subnet_ips.add_new_child('ip-range', ip_range)
- if self.parameters.get('ipspace'):
- subnet_modify.add_new_child('ipspace', self.parameters.get('ipspace'))
- if self.parameters.get('subnet'):
- subnet_modify.add_new_child('subnet', self.parameters.get('subnet'))
-
- try:
- self.server.invoke_successfully(subnet_modify, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying subnet %s: %s' % (self.parameters.get('name'), to_native(error)),
- exception=traceback.format_exc())
-
- def rename_subnet(self):
- """
- TODO
- """
- options = {'subnet-name': self.parameters.get('from_name'),
- 'new-name': self.parameters.get('name')}
-
- subnet_rename = netapp_utils.zapi.NaElement.create_node_with_children(
- 'net-subnet-rename', **options)
-
- if self.parameters.get('ipspace'):
- subnet_rename.add_new_child('ipspace', self.parameters.get('ipspace'))
-
- try:
- self.server.invoke_successfully(subnet_rename, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error renaming subnet %s: %s' % (self.parameters.get('name'), to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- '''Apply action to subnet'''
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_net_subnet", cserver)
- current = self.get_subnet()
- cd_action, rename = None, None
-
- if self.parameters.get('from_name'):
- rename = self.na_helper.is_rename_action(self.get_subnet(self.parameters.get('from_name')), current)
- if rename is False:
- self.module.fail_json(msg="Error renaming: subnet %s does not exist" %
- self.parameters.get('from_name'))
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
-
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- for attribute in modify:
- if attribute in ['broadcast_domain']:
- self.module.fail_json(msg='Error modifying subnet %s: cannot modify broadcast_domain parameter.' % self.parameters.get('name'))
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_subnet()
- # If rename is True, cd_action is NOne but modify could be true
- if cd_action == 'create':
- for attribute in ['subnet', 'broadcast_domain']:
- if not self.parameters.get(attribute):
- self.module.fail_json(msg='Error - missing required arguments: %s.' % attribute)
- self.create_subnet()
- elif cd_action == 'delete':
- self.delete_subnet()
- elif modify:
- self.modify_subnet()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Creates the NetApp ONTAP Net Route object and runs the correct play task
- """
- subnet_obj = NetAppOntapSubnet()
- subnet_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_net_vlan.py b/lib/ansible/modules/storage/netapp/na_ontap_net_vlan.py
deleted file mode 100644
index 432b608ad9..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_net_vlan.py
+++ /dev/null
@@ -1,186 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_net_vlan
-short_description: NetApp ONTAP network VLAN
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create or Delete a network VLAN
-options:
- state:
- description:
- - Whether the specified network VLAN should exist or not
- choices: ['present', 'absent']
- default: present
- parent_interface:
- description:
- - The interface that hosts the VLAN interface.
- required: true
- vlanid:
- description:
- - The VLAN id. Ranges from 1 to 4094.
- required: true
- node:
- description:
- - Node name of VLAN interface.
- required: true
-notes:
- - The C(interface_name) option has been removed and should be deleted from playbooks
-'''
-
-EXAMPLES = """
- - name: create VLAN
- na_ontap_net_vlan:
- state: present
- vlanid: 13
- node: "{{ vlan node }}"
- parent_interface: "{{ vlan parent interface name }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
-"""
-
-RETURN = """
-
-"""
-
-from ansible.module_utils.basic import AnsibleModule
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapVlan(object):
- """
- Created, and destorys Net Vlans's
- """
- def __init__(self):
- """
- Initializes the NetAppOntapVlan function
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- parent_interface=dict(required=True, type='str'),
- vlanid=dict(required=True, type='str'),
- node=dict(required=True, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- p = self.module.params
-
- # set up state variables
- self.state = p['state']
- self.parent_interface = p['parent_interface']
- self.vlanid = p['vlanid']
- self.node = p['node']
- self.interface_name = str(p['parent_interface']) + '-' + str(self.vlanid)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- return
-
- def create_vlan(self):
- """
- Creates a new vlan
- """
- vlan_obj = netapp_utils.zapi.NaElement("net-vlan-create")
- vlan_info = self.create_vlan_info()
-
- vlan_obj.add_child_elem(vlan_info)
- self.server.invoke_successfully(vlan_obj, True)
-
- def delete_vlan(self):
- """
- Deletes a vland
- """
- vlan_obj = netapp_utils.zapi.NaElement("net-vlan-delete")
- vlan_info = self.create_vlan_info()
-
- vlan_obj.add_child_elem(vlan_info)
- self.server.invoke_successfully(vlan_obj, True)
-
- def does_vlan_exist(self):
- """
- Checks to see if a vlan already exists or not
- :return: Returns True if the vlan exists, false if it doesn't
- """
- vlan_obj = netapp_utils.zapi.NaElement("net-vlan-get")
- vlan_obj.add_new_child("interface-name", self.interface_name)
- vlan_obj.add_new_child("node", self.node)
- try:
- result = self.server.invoke_successfully(vlan_obj, True)
- result.get_child_by_name("attributes").get_child_by_name("vlan-info").get_child_by_name("interface-name")
- except netapp_utils.zapi.NaApiError:
- return False
- return True
-
- def create_vlan_info(self):
- """
- Create a vlan_info object to be used in a create/delete
- :return:
- """
- vlan_info = netapp_utils.zapi.NaElement("vlan-info")
-
- # set up the vlan_info object:
- vlan_info.add_new_child("parent-interface", self.parent_interface)
- vlan_info.add_new_child("vlanid", self.vlanid)
- vlan_info.add_new_child("node", self.node)
- return vlan_info
-
- def apply(self):
- """
- check the option in the playbook to see what needs to be done
- :return:
- """
- changed = False
- result = None
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_net_vlan", cserver)
- existing_vlan = self.does_vlan_exist()
- if existing_vlan:
- if self.state == 'absent': # delete
- changed = True
- else:
- if self.state == 'present': # create
- changed = True
- if changed:
- if self.module.check_mode:
- pass
- else:
- if self.state == 'present':
- self.create_vlan()
- elif self.state == 'absent':
- self.delete_vlan()
- self.module.exit_json(changed=changed, meta=result)
-
-
-def main():
- """
- Creates the NetApp Ontap vlan object, and runs the correct play task.
- """
- v = NetAppOntapVlan()
- v.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_nfs.py b/lib/ansible/modules/storage/netapp/na_ontap_nfs.py
deleted file mode 100644
index e691ff6e95..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_nfs.py
+++ /dev/null
@@ -1,576 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = """
-module: na_ontap_nfs
-short_description: NetApp ONTAP NFS status
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Enable or disable NFS on ONTAP
-options:
- state:
- description:
- - Whether NFS should exist or not.
- choices: ['present', 'absent']
- default: present
- service_state:
- description:
- - Whether the specified NFS should be enabled or disabled. Creates NFS service if does not exist.
- choices: ['started', 'stopped']
- vserver:
- description:
- - Name of the vserver to use.
- required: true
- nfsv3:
- description:
- - status of NFSv3.
- choices: ['enabled', 'disabled']
- nfsv3_fsid_change:
- description:
- - status of if NFSv3 clients see change in FSID as they traverse filesystems.
- choices: ['enabled', 'disabled']
- version_added: '2.7'
- nfsv4_fsid_change:
- description:
- - status of if NFSv4 clients see change in FSID as they traverse filesystems.
- choices: ['enabled', 'disabled']
- version_added: '2.9'
- nfsv4:
- description:
- - status of NFSv4.
- choices: ['enabled', 'disabled']
- nfsv41:
- description:
- - status of NFSv41.
- aliases: ['nfsv4.1']
- choices: ['enabled', 'disabled']
- nfsv41_pnfs:
- description:
- - status of NFSv41 pNFS.
- choices: ['enabled', 'disabled']
- version_added: '2.9'
- nfsv4_numeric_ids:
- description:
- - status of NFSv4 numeric ID's.
- choices: ['enabled', 'disabled']
- version_added: '2.9'
- vstorage_state:
- description:
- - status of vstorage_state.
- choices: ['enabled', 'disabled']
- nfsv4_id_domain:
- description:
- - Name of the nfsv4_id_domain to use.
- nfsv40_acl:
- description:
- - status of NFS v4.0 ACL feature
- choices: ['enabled', 'disabled']
- version_added: '2.7'
- nfsv40_read_delegation:
- description:
- - status for NFS v4.0 read delegation feature.
- choices: ['enabled', 'disabled']
- version_added: '2.7'
- nfsv40_write_delegation:
- description:
- - status for NFS v4.0 write delegation feature.
- choices: ['enabled', 'disabled']
- version_added: '2.7'
- nfsv41_acl:
- description:
- - status of NFS v4.1 ACL feature
- choices: ['enabled', 'disabled']
- version_added: '2.7'
- nfsv41_read_delegation:
- description:
- - status for NFS v4.1 read delegation feature.
- choices: ['enabled', 'disabled']
- version_added: '2.7'
- nfsv41_write_delegation:
- description:
- - status for NFS v4.1 write delegation feature.
- choices: ['enabled', 'disabled']
- version_added: '2.7'
- nfsv40_referrals:
- description:
- - status for NFS v4.0 referrals.
- choices: ['enabled', 'disabled']
- version_added: '2.9'
- nfsv41_referrals:
- description:
- - status for NFS v4.1 referrals.
- choices: ['enabled', 'disabled']
- version_added: '2.9'
- tcp:
- description:
- - Enable TCP (support from ONTAP 9.3 onward).
- choices: ['enabled', 'disabled']
- udp:
- description:
- - Enable UDP (support from ONTAP 9.3 onward).
- choices: ['enabled', 'disabled']
- showmount:
- description:
- - Whether SVM allows showmount
- choices: ['enabled', 'disabled']
- version_added: '2.7'
- tcp_max_xfer_size:
- description:
- - TCP Maximum Transfer Size (bytes). The default value is 65536.
- version_added: '2.8'
- type: int
-
-"""
-
-EXAMPLES = """
- - name: change nfs status
- na_ontap_nfs:
- state: present
- service_state: stopped
- vserver: vs_hack
- nfsv3: disabled
- nfsv4: disabled
- nfsv41: enabled
- tcp: disabled
- udp: disabled
- vstorage_state: disabled
- nfsv4_id_domain: example.com
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPNFS(object):
- """ object initialize and class methods """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- service_state=dict(required=False, choices=['started', 'stopped']),
- vserver=dict(required=True, type='str'),
- nfsv3=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv3_fsid_change=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv4_fsid_change=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv4=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv41=dict(required=False, default=None, choices=['enabled', 'disabled'], aliases=['nfsv4.1']),
- nfsv41_pnfs=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv4_numeric_ids=dict(required=False, default=None, choices=['enabled', 'disabled']),
- vstorage_state=dict(required=False, default=None, choices=['enabled', 'disabled']),
- tcp=dict(required=False, default=None, choices=['enabled', 'disabled']),
- udp=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv4_id_domain=dict(required=False, type='str', default=None),
- nfsv40_acl=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv40_read_delegation=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv40_referrals=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv40_write_delegation=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv41_acl=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv41_read_delegation=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv41_referrals=dict(required=False, default=None, choices=['enabled', 'disabled']),
- nfsv41_write_delegation=dict(required=False, default=None, choices=['enabled', 'disabled']),
- showmount=dict(required=False, default=None, choices=['enabled', 'disabled']),
- tcp_max_xfer_size=dict(required=False, default=None, type='int')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- parameters = self.module.params
-
- # set up service_state variables
- self.state = parameters['state']
- self.service_state = parameters['service_state']
- self.vserver = parameters['vserver']
- self.nfsv3 = parameters['nfsv3']
- self.nfsv3_fsid_change = parameters['nfsv3_fsid_change']
- self.nfsv4_fsid_change = parameters['nfsv4_fsid_change']
- self.nfsv4 = parameters['nfsv4']
- self.nfsv41 = parameters['nfsv41']
- self.vstorage_state = parameters['vstorage_state']
- self.nfsv4_id_domain = parameters['nfsv4_id_domain']
- self.udp = parameters['udp']
- self.tcp = parameters['tcp']
- self.nfsv40_acl = parameters['nfsv40_acl']
- self.nfsv40_read_delegation = parameters['nfsv40_read_delegation']
- self.nfsv40_referrals = parameters['nfsv40_referrals']
- self.nfsv40_write_delegation = parameters['nfsv40_write_delegation']
- self.nfsv41_acl = parameters['nfsv41_acl']
- self.nfsv41_read_delegation = parameters['nfsv41_read_delegation']
- self.nfsv41_referrals = parameters['nfsv41_referrals']
- self.nfsv41_write_delegation = parameters['nfsv41_write_delegation']
- self.nfsv41_pnfs = parameters['nfsv41_pnfs']
- self.nfsv4_numeric_ids = parameters['nfsv4_numeric_ids']
- self.showmount = parameters['showmount']
- self.tcp_max_xfer_size = parameters['tcp_max_xfer_size']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver)
-
- def get_nfs_service(self):
- """
- Return details about nfs
- :param:
- name : name of the vserver
- :return: Details about nfs. None if not found.
- :rtype: dict
- """
- nfs_get_iter = netapp_utils.zapi.NaElement('nfs-service-get-iter')
- nfs_info = netapp_utils.zapi.NaElement('nfs-info')
- nfs_info.add_new_child('vserver', self.vserver)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(nfs_info)
- nfs_get_iter.add_child_elem(query)
- result = self.server.invoke_successfully(nfs_get_iter, True)
- nfs_details = None
- # check if job exists
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) >= 1:
- attributes_list = result.get_child_by_name('attributes-list').get_child_by_name('nfs-info')
- is_nfsv3_enabled = attributes_list.get_child_content('is-nfsv3-enabled')
- is_nfsv3_fsid_change_enabled = attributes_list.get_child_content('is-nfsv3-fsid-change-enabled')
- is_nfsv4_fsid_change_enabled = attributes_list.get_child_content('is-nfsv4-fsid-change-enabled')
- is_nfsv40_enabled = attributes_list.get_child_content('is-nfsv40-enabled')
- is_nfsv41_enabled = attributes_list.get_child_content('is-nfsv41-enabled')
- is_vstorage_enabled = attributes_list.get_child_content('is-vstorage-enabled')
- nfsv4_id_domain_value = attributes_list.get_child_content('nfsv4-id-domain')
- is_tcp_enabled = attributes_list.get_child_content('is-tcp-enabled')
- is_udp_enabled = attributes_list.get_child_content('is-udp-enabled')
- is_nfsv40_acl_enabled = attributes_list.get_child_content('is-nfsv40-acl-enabled')
- is_nfsv40_write_delegation_enabled = attributes_list.get_child_content('is-nfsv40-write-delegation-enabled')
- is_nfsv40_read_delegation_enabled = attributes_list.get_child_content('is-nfsv40-read-delegation-enabled')
- is_nfsv40_referrals_enabled = attributes_list.get_child_content('is-nfsv40-referrals-enabled')
- is_nfsv41_acl_enabled = attributes_list.get_child_content('is-nfsv41-acl-enabled')
- is_nfsv41_write_delegation_enabled = attributes_list.get_child_content('is-nfsv41-write-delegation-enabled')
- is_nfsv41_read_delegation_enabled = attributes_list.get_child_content('is-nfsv41-read-delegation-enabled')
- is_nfsv41_referrals_enabled = attributes_list.get_child_content('is-nfsv41-referrals-enabled')
- is_nfsv41_pnfs_enabled = attributes_list.get_child_content('is-nfsv41-pnfs-enabled')
- is_nfsv4_numeric_ids_enabled = attributes_list.get_child_content('is-nfsv4-numeric-ids-enabled')
- is_showmount_enabled = attributes_list.get_child_content('showmount')
- tcp_max_xfer_size = attributes_list.get_child_content('tcp-max-xfer-size')
- nfs_details = {
- 'is_nfsv3_enabled': is_nfsv3_enabled,
- 'is_nfsv3_fsid_change_enabled': is_nfsv3_fsid_change_enabled,
- 'is_nfsv4_fsid_change_enabled': is_nfsv4_fsid_change_enabled,
- 'is_nfsv40_enabled': is_nfsv40_enabled,
- 'is_nfsv41_enabled': is_nfsv41_enabled,
- 'is_nfsv41_pnfs_enabled': is_nfsv41_pnfs_enabled,
- 'is_nfsv4_numeric_ids_enabled': is_nfsv4_numeric_ids_enabled,
- 'is_vstorage_enabled': is_vstorage_enabled,
- 'nfsv4_id_domain': nfsv4_id_domain_value,
- 'is_tcp_enabled': is_tcp_enabled,
- 'is_udp_enabled': is_udp_enabled,
- 'is_nfsv40_acl_enabled': is_nfsv40_acl_enabled,
- 'is_nfsv40_read_delegation_enabled': is_nfsv40_read_delegation_enabled,
- 'is_nfsv40_referrals_enabled': is_nfsv40_referrals_enabled,
- 'is_nfsv40_write_delegation_enabled': is_nfsv40_write_delegation_enabled,
- 'is_nfsv41_acl_enabled': is_nfsv41_acl_enabled,
- 'is_nfsv41_read_delegation_enabled': is_nfsv41_read_delegation_enabled,
- 'is_nfsv41_referrals_enabled': is_nfsv41_referrals_enabled,
- 'is_nfsv41_write_delegation_enabled': is_nfsv41_write_delegation_enabled,
- 'is_showmount_enabled': is_showmount_enabled,
- 'tcp_max_xfer_size': tcp_max_xfer_size
- }
- return nfs_details
-
- def get_nfs_status(self):
- """
- Return status of nfs
- :param:
- name : Name of the vserver
- :return: status of nfs. None if not found.
- :rtype: bool
- """
- nfs_status = netapp_utils.zapi.NaElement('nfs-status')
- result = self.server.invoke_successfully(nfs_status, True)
- return_value = result.get_child_content('is-enabled')
-
- return return_value
-
- def enable_nfs(self):
- """
- enable nfs (online). If the NFS service was not explicitly created,
- this API will create one with default options.
- """
- nfs_enable = netapp_utils.zapi.NaElement.create_node_with_children('nfs-enable')
- try:
- self.server.invoke_successfully(nfs_enable,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error changing the service_state of nfs %s to %s: %s' %
- (self.vserver, self.service_state, to_native(error)),
- exception=traceback.format_exc())
-
- def disable_nfs(self):
- """
- disable nfs (offline).
- """
- nfs_disable = netapp_utils.zapi.NaElement.create_node_with_children('nfs-disable')
- try:
- self.server.invoke_successfully(nfs_disable,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error changing the service_state of nfs %s to %s: %s' %
- (self.vserver, self.service_state, to_native(error)),
- exception=traceback.format_exc())
-
- def modify_nfs(self):
- """
- modify nfs service
- """
- nfs_modify = netapp_utils.zapi.NaElement('nfs-service-modify')
- if self.nfsv3 == 'enabled':
- nfs_modify.add_new_child('is-nfsv3-enabled', 'true')
- elif self.nfsv3 == 'disabled':
- nfs_modify.add_new_child('is-nfsv3-enabled', 'false')
- if self.nfsv3_fsid_change == 'enabled':
- nfs_modify.add_new_child('is-nfsv3-fsid-change-enabled', 'true')
- elif self.nfsv3_fsid_change == 'disabled':
- nfs_modify.add_new_child('is-nfsv3-fsid-change-enabled', 'false')
- if self.nfsv4_fsid_change == 'enabled':
- nfs_modify.add_new_child('is-nfsv4-fsid-change-enabled', 'true')
- elif self.nfsv4_fsid_change == 'disabled':
- nfs_modify.add_new_child('is-nfsv4-fsid-change-enabled', 'false')
- if self.nfsv4 == 'enabled':
- nfs_modify.add_new_child('is-nfsv40-enabled', 'true')
- elif self.nfsv4 == 'disabled':
- nfs_modify.add_new_child('is-nfsv40-enabled', 'false')
- if self.nfsv41 == 'enabled':
- nfs_modify.add_new_child('is-nfsv41-enabled', 'true')
- elif self.nfsv41 == 'disabled':
- nfs_modify.add_new_child('is-nfsv41-enabled', 'false')
- if self.vstorage_state == 'enabled':
- nfs_modify.add_new_child('is-vstorage-enabled', 'true')
- elif self.vstorage_state == 'disabled':
- nfs_modify.add_new_child('is-vstorage-enabled', 'false')
- if self.tcp == 'enabled':
- nfs_modify.add_new_child('is-tcp-enabled', 'true')
- elif self.tcp == 'disabled':
- nfs_modify.add_new_child('is-tcp-enabled', 'false')
- if self.udp == 'enabled':
- nfs_modify.add_new_child('is-udp-enabled', 'true')
- elif self.udp == 'disabled':
- nfs_modify.add_new_child('is-udp-enabled', 'false')
- if self.nfsv40_acl == 'enabled':
- nfs_modify.add_new_child('is-nfsv40-acl-enabled', 'true')
- elif self.nfsv40_acl == 'disabled':
- nfs_modify.add_new_child('is-nfsv40-acl-enabled', 'false')
- if self.nfsv40_read_delegation == 'enabled':
- nfs_modify.add_new_child('is-nfsv40-read-delegation-enabled', 'true')
- elif self.nfsv40_read_delegation == 'disabled':
- nfs_modify.add_new_child('is-nfsv40-read-delegation-enabled', 'false')
- if self.nfsv40_referrals == 'enabled':
- nfs_modify.add_new_child('is-nfsv40-referrals-enabled', 'true')
- elif self.nfsv40_referrals == 'disabled':
- nfs_modify.add_new_child('is-nfsv40-referrals-enabled', 'false')
- if self.nfsv40_write_delegation == 'enabled':
- nfs_modify.add_new_child('is-nfsv40-write-delegation-enabled', 'true')
- elif self.nfsv40_write_delegation == 'disabled':
- nfs_modify.add_new_child('is-nfsv40-write-delegation-enabled', 'false')
- if self.nfsv41_acl == 'enabled':
- nfs_modify.add_new_child('is-nfsv41-acl-enabled', 'true')
- elif self.nfsv41_acl == 'disabled':
- nfs_modify.add_new_child('is-nfsv41-acl-enabled', 'false')
- if self.nfsv41_read_delegation == 'enabled':
- nfs_modify.add_new_child('is-nfsv41-read-delegation-enabled', 'true')
- elif self.nfsv41_read_delegation == 'disabled':
- nfs_modify.add_new_child('is-nfsv41-read-delegation-enabled', 'false')
- if self.nfsv41_referrals == 'enabled':
- nfs_modify.add_new_child('is-nfsv41-referrals-enabled', 'true')
- elif self.nfsv41_referrals == 'disabled':
- nfs_modify.add_new_child('is-nfsv41-referrals-enabled', 'false')
- if self.nfsv41_write_delegation == 'enabled':
- nfs_modify.add_new_child('is-nfsv41-write-delegation-enabled', 'true')
- elif self.nfsv41_write_delegation == 'disabled':
- nfs_modify.add_new_child('is-nfsv41-write-delegation-enabled', 'false')
- if self.nfsv41_pnfs == 'enabled':
- nfs_modify.add_new_child('is-nfsv41-pnfs-enabled', 'true')
- elif self.nfsv41_pnfs == 'disabled':
- nfs_modify.add_new_child('is-nfsv41-pnfs-enabled', 'false')
- if self.nfsv4_numeric_ids == 'enabled':
- nfs_modify.add_new_child('is-nfsv4-numeric-ids-enabled', 'true')
- elif self.nfsv4_numeric_ids == 'disabled':
- nfs_modify.add_new_child('is-nfsv4-numeric-ids-enabled', 'false')
- if self.showmount == 'enabled':
- nfs_modify.add_new_child('showmount', 'true')
- elif self.showmount == 'disabled':
- nfs_modify.add_new_child('showmount', 'false')
- if self.tcp_max_xfer_size is not None:
- nfs_modify.add_new_child('tcp-max-xfer-size', str(self.tcp_max_xfer_size))
- try:
- self.server.invoke_successfully(nfs_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying nfs: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def modify_nfsv4_id_domain(self):
- """
- modify nfs service
- """
- nfsv4_id_domain_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'nfs-service-modify', **{'nfsv4-id-domain': self.nfsv4_id_domain})
- if nfsv4_id_domain_modify is not None:
- try:
- self.server.invoke_successfully(nfsv4_id_domain_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying nfs: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def delete_nfs(self):
- """
- delete nfs service.
- """
- nfs_delete = netapp_utils.zapi.NaElement.create_node_with_children('nfs-service-destroy')
- try:
- self.server.invoke_successfully(nfs_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting nfs: %s' %
- (to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """Apply action to nfs"""
- changed = False
- nfs_exists = False
- modify_nfs = False
- enable_nfs = False
- disable_nfs = False
- netapp_utils.ems_log_event("na_ontap_nfs", self.server)
- nfs_enabled = self.get_nfs_status()
- nfs_service_details = self.get_nfs_service()
- is_nfsv4_id_domain_changed = False
-
- def state_changed(expected, current):
- if expected == "enabled" and current == "true":
- return False
- if expected == "disabled" and current == "false":
- return False
- return True
-
- def is_modify_needed():
- if (((self.nfsv3 is not None) and state_changed(self.nfsv3, nfs_service_details['is_nfsv3_enabled'])) or
- ((self.nfsv3_fsid_change is not None) and state_changed(self.nfsv3_fsid_change, nfs_service_details['is_nfsv3_fsid_change_enabled'])) or
- ((self.nfsv4_fsid_change is not None) and state_changed(self.nfsv4_fsid_change, nfs_service_details['is_nfsv4_fsid_change_enabled'])) or
- ((self.nfsv4 is not None) and state_changed(self.nfsv4, nfs_service_details['is_nfsv40_enabled'])) or
- ((self.nfsv41 is not None) and state_changed(self.nfsv41, nfs_service_details['is_nfsv41_enabled'])) or
- ((self.nfsv41_pnfs is not None) and state_changed(self.nfsv41_pnfs, nfs_service_details['is_nfsv41_pnfs_enabled'])) or
- ((self.nfsv4_numeric_ids is not None) and state_changed(self.nfsv4_numeric_ids, nfs_service_details['is_nfsv4_numeric_ids_enabled'])) or
- ((self.tcp is not None) and state_changed(self.tcp, nfs_service_details['is_tcp_enabled'])) or
- ((self.udp is not None) and state_changed(self.udp, nfs_service_details['is_udp_enabled'])) or
- ((self.nfsv40_acl is not None) and state_changed(self.nfsv40_acl, nfs_service_details['is_nfsv40_acl_enabled'])) or
- ((self.nfsv40_read_delegation is not None) and state_changed(self.nfsv40_read_delegation,
- nfs_service_details['is_nfsv40_read_delegation_enabled'])) or
- ((self.nfsv40_write_delegation is not None) and state_changed(self.nfsv40_write_delegation,
- nfs_service_details['is_nfsv40_write_delegation_enabled'])) or
- ((self.nfsv41_acl is not None) and state_changed(self.nfsv41_acl, nfs_service_details['is_nfsv41_acl_enabled'])) or
- ((self.nfsv41_read_delegation is not None) and state_changed(self.nfsv41_read_delegation,
- nfs_service_details['is_nfsv41_read_delegation_enabled'])) or
- ((self.nfsv41_write_delegation is not None) and state_changed(self.nfsv41_write_delegation,
- nfs_service_details['is_nfsv41_write_delegation_enabled'])) or
- ((self.nfsv40_referrals is not None) and state_changed(self.nfsv40_referrals,
- nfs_service_details['is_nfsv40_referrals_enabled'])) or
- ((self.nfsv41_referrals is not None) and state_changed(self.nfsv41_referrals,
- nfs_service_details['is_nfsv41_referrals_enabled'])) or
- ((self.showmount is not None) and state_changed(self.showmount, nfs_service_details['is_showmount_enabled'])) or
- ((self.vstorage_state is not None) and state_changed(self.vstorage_state, nfs_service_details['is_vstorage_enabled'])) or
- ((self.tcp_max_xfer_size is not None) and int(self.tcp_max_xfer_size) != int(nfs_service_details['tcp_max_xfer_size']))):
- return True
- return False
-
- def is_domain_changed():
- if (self.nfsv4_id_domain is not None) and (self.nfsv4_id_domain != nfs_service_details['nfsv4_id_domain']):
- return True
- return False
-
- if nfs_service_details:
- nfs_exists = True
- if self.state == 'absent': # delete
- changed = True
- elif self.state == 'present': # modify
- if self.service_state == 'started' and nfs_enabled == 'false':
- enable_nfs = True
- changed = True
- elif self.service_state == 'stopped' and nfs_enabled == 'true':
- disable_nfs = True
- changed = True
- if is_modify_needed():
- modify_nfs = True
- changed = True
- if is_domain_changed():
- is_nfsv4_id_domain_changed = True
- changed = True
- else:
- if self.state == 'present': # create
- changed = True
- if changed:
- if self.module.check_mode:
- pass
- else:
- if self.state == 'present': # execute create
- if not nfs_exists:
- self.enable_nfs()
- nfs_service_details = self.get_nfs_service()
- if self.service_state == 'stopped':
- self.disable_nfs()
- if is_modify_needed():
- self.modify_nfs()
- if is_domain_changed():
- self.modify_nfsv4_id_domain()
- else:
- if enable_nfs:
- self.enable_nfs()
- elif disable_nfs:
- self.disable_nfs()
- if modify_nfs:
- self.modify_nfs()
- if is_nfsv4_id_domain_changed:
- self.modify_nfsv4_id_domain()
- elif self.state == 'absent': # execute delete
- self.delete_nfs()
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- """ Create object and call apply """
- obj = NetAppONTAPNFS()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_node.py b/lib/ansible/modules/storage/netapp/na_ontap_node.py
deleted file mode 100644
index 1e68f92750..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_node.py
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_node
-short_description: NetApp ONTAP Rename a node.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.7'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Rename an ONTAP node.
-options:
- name:
- description:
- - The new name for the node
- required: true
-
- from_name:
- description:
- - The name of the node to be renamed. If I(name) already exists, no action will be performed.
- required: true
-
-'''
-
-EXAMPLES = """
-- name: rename node
- na_ontap_node:
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- from_name: laurentn-vsim1
- name: laurentncluster-2
-"""
-
-RETURN = """
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapNode(object):
- """
- Rename node
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- name=dict(required=True, type='str'),
- from_name=dict(required=True, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.cluster = netapp_utils.setup_na_ontap_zapi(module=self.module)
- return
-
- def rename_node(self):
- """
- Rename an existing node
- :return: none
- """
- node_obj = netapp_utils.zapi.NaElement('system-node-rename')
- node_obj.add_new_child('node', self.parameters['from_name'])
- node_obj.add_new_child('new-name', self.parameters['name'])
- try:
- self.cluster.invoke_successfully(node_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating node: %s' %
- (to_native(error)),
- exception=traceback.format_exc())
-
- def get_node(self, name):
- node_obj = netapp_utils.zapi.NaElement('system-node-get')
- node_obj.add_new_child('node', name)
- try:
- self.cluster.invoke_successfully(node_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- if to_native(error.code) == "13115":
- # 13115 (EINVALIDINPUTERROR) if the node does not exist
- return None
- else:
- self.module.fail_json(msg=to_native(
- error), exception=traceback.format_exc())
- return True
-
- def apply(self):
- # logging ems event
- results = netapp_utils.get_cserver(self.cluster)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_node", cserver)
-
- exists = self.get_node(self.parameters['name'])
- from_exists = self.get_node(self.parameters['from_name'])
- changed = False
- if exists:
- pass
- else:
- if from_exists:
- self.rename_node()
- changed = True
- else:
- self.module.fail_json(msg='Error renaming node, from_name %s does not exist' % self.parameters['from_name'])
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Start, Stop and Enable node services.
- """
- obj = NetAppOntapNode()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_ntp.py b/lib/ansible/modules/storage/netapp/na_ontap_ntp.py
deleted file mode 100644
index 6c57880587..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_ntp.py
+++ /dev/null
@@ -1,226 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = """
-module: na_ontap_ntp
-short_description: NetApp ONTAP NTP server
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create or delete or modify NTP server in ONTAP
-options:
- state:
- description:
- - Whether the specified NTP server should exist or not.
- choices: ['present', 'absent']
- default: 'present'
- server_name:
- description:
- - The name of the NTP server to manage.
- required: True
- version:
- description:
- - give version for NTP server
- choices: ['auto', '3', '4']
- default: 'auto'
-"""
-
-EXAMPLES = """
- - name: Create NTP server
- na_ontap_ntp:
- state: present
- version: auto
- server_name: "{{ server_name }}"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Delete NTP server
- na_ontap_ntp:
- state: absent
- server_name: "{{ server_name }}"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapNTPServer(object):
- """ object initialize and class methods """
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- server_name=dict(required=True, type='str'),
- version=dict(required=False, type='str', default='auto',
- choices=['auto', '3', '4']),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- parameters = self.module.params
-
- # set up state variables
- self.state = parameters['state']
- self.server_name = parameters['server_name']
- self.version = parameters['version']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def get_ntp_server(self):
- """
- Return details about the ntp server
- :param:
- name : Name of the server_name
- :return: Details about the ntp server. None if not found.
- :rtype: dict
- """
- ntp_iter = netapp_utils.zapi.NaElement('ntp-server-get-iter')
- ntp_info = netapp_utils.zapi.NaElement('ntp-server-info')
- ntp_info.add_new_child('server-name', self.server_name)
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(ntp_info)
-
- ntp_iter.add_child_elem(query)
- result = self.server.invoke_successfully(ntp_iter, True)
- return_value = None
-
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
-
- ntp_server_name = result.get_child_by_name('attributes-list').\
- get_child_by_name('ntp-server-info').\
- get_child_content('server-name')
- server_version = result.get_child_by_name('attributes-list').\
- get_child_by_name('ntp-server-info').\
- get_child_content('version')
- return_value = {
- 'server-name': ntp_server_name,
- 'version': server_version
- }
-
- return return_value
-
- def create_ntp_server(self):
- """
- create ntp server.
- """
- ntp_server_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'ntp-server-create', **{'server-name': self.server_name,
- 'version': self.version
- })
-
- try:
- self.server.invoke_successfully(ntp_server_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating ntp server %s: %s'
- % (self.server_name, to_native(error)),
- exception=traceback.format_exc())
-
- def delete_ntp_server(self):
- """
- delete ntp server.
- """
- ntp_server_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'ntp-server-delete', **{'server-name': self.server_name})
-
- try:
- self.server.invoke_successfully(ntp_server_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting ntp server %s: %s'
- % (self.server_name, to_native(error)),
- exception=traceback.format_exc())
-
- def modify_version(self):
- """
- modify the version.
- """
- ntp_modify_versoin = netapp_utils.zapi.NaElement.create_node_with_children(
- 'ntp-server-modify',
- **{'server-name': self.server_name, 'version': self.version})
- try:
- self.server.invoke_successfully(ntp_modify_versoin,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying version for ntp server %s: %s'
- % (self.server_name, to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """Apply action to ntp-server"""
-
- changed = False
- ntp_modify = False
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_ntp", cserver)
- ntp_server_details = self.get_ntp_server()
- if ntp_server_details is not None:
- if self.state == 'absent': # delete
- changed = True
- elif self.state == 'present' and self.version:
- # modify version
- if self.version != ntp_server_details['version']:
- ntp_modify = True
- changed = True
- else:
- if self.state == 'present': # create
- changed = True
-
- if changed:
- if self.module.check_mode:
- pass
- else:
- if self.state == 'present':
- if ntp_server_details is None:
- self.create_ntp_server()
- elif ntp_modify:
- self.modify_version()
- elif self.state == 'absent':
- self.delete_ntp_server()
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- """ Create object and call apply """
- ntp_obj = NetAppOntapNTPServer()
- ntp_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_nvme.py b/lib/ansible/modules/storage/netapp/na_ontap_nvme.py
deleted file mode 100644
index 61e32c64fc..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_nvme.py
+++ /dev/null
@@ -1,209 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Create/Delete NVMe Service
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_nvme
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified NVMe should exist or not.
- default: present
- vserver:
- description:
- - Name of the vserver to use.
- required: true
- status_admin:
- description:
- - Whether the status of NVMe should be up or down
- type: bool
-short_description: "NetApp ONTAP Manage NVMe Service"
-version_added: "2.8"
-'''
-
-EXAMPLES = """
-
- - name: Create NVMe
- na_ontap_nvme:
- state: present
- status_admin: False
- vserver: "{{ vserver }}"
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
-
- - name: Modify NVMe
- na_ontap_nvme:
- state: present
- status_admin: True
- vserver: "{{ vserver }}"
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
-
- - name: Delete NVMe
- na_ontap_nvme:
- state: absent
- vserver: "{{ vserver }}"
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPNVMe(object):
- """
- Class with NVMe service methods
- """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- status_admin=dict(required=False, type='bool')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_nvme(self):
- """
- Get current nvme details
- :return: dict if nvme exists, None otherwise
- """
- nvme_get = netapp_utils.zapi.NaElement('nvme-get-iter')
- query = {
- 'query': {
- 'nvme-target-service-info': {
- 'vserver': self.parameters['vserver']
- }
- }
- }
- nvme_get.translate_struct(query)
- try:
- result = self.server.invoke_successfully(nvme_get, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching nvme info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- attributes_list = result.get_child_by_name('attributes-list')
- nvme_info = attributes_list.get_child_by_name('nvme-target-service-info')
- return_value = {'status_admin': nvme_info.get_child_content('is-available')}
- return return_value
- return None
-
- def create_nvme(self):
- """
- Create NVMe service
- """
- nvme_create = netapp_utils.zapi.NaElement('nvme-create')
- if self.parameters.get('status_admin') is not None:
- options = {'is-available': self.parameters['status_admin']}
- nvme_create.translate_struct(options)
- try:
- self.server.invoke_successfully(nvme_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating nvme for vserver %s: %s'
- % (self.parameters['vserver'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_nvme(self):
- """
- Delete NVMe service
- """
- nvme_delete = netapp_utils.zapi.NaElement('nvme-delete')
- try:
- self.server.invoke_successfully(nvme_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting nvme for vserver %s: %s'
- % (self.parameters['vserver'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_nvme(self, status=None):
- """
- Modify NVMe service
- """
- if status is None:
- status = self.parameters['status_admin']
- options = {'is-available': status}
- nvme_modify = netapp_utils.zapi.NaElement('nvme-modify')
- nvme_modify.translate_struct(options)
- try:
- self.server.invoke_successfully(nvme_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying nvme for vserver %s: %s'
- % (self.parameters['vserver'], to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Apply action to NVMe service
- """
- netapp_utils.ems_log_event("na_ontap_nvme", self.server)
- current = self.get_nvme()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if self.parameters.get('status_admin') is not None:
- self.parameters['status_admin'] = self.na_helper.get_value_for_bool(False, self.parameters['status_admin'])
- if cd_action is None and self.parameters['state'] == 'present':
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_nvme()
- elif cd_action == 'delete':
- # NVMe status_admin needs to be down before deleting it
- self.modify_nvme('false')
- self.delete_nvme()
- elif modify:
- self.modify_nvme()
-
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """Execute action"""
- community_obj = NetAppONTAPNVMe()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_nvme_namespace.py b/lib/ansible/modules/storage/netapp/na_ontap_nvme_namespace.py
deleted file mode 100644
index aa0a4a34e8..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_nvme_namespace.py
+++ /dev/null
@@ -1,195 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Create/Delete NVME namespace
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_nvme_namespace
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified namespace should exist or not.
- default: present
- vserver:
- description:
- - Name of the vserver to use.
- required: true
- ostype:
- description:
- - Specifies the ostype for initiators
- choices: ['windows', 'linux', 'vmware', 'xen', 'hyper_v']
- size:
- description:
- - Size in bytes.
- Range is [0..2^63-1].
- type: int
- path:
- description:
- - Namespace path.
- type: str
-short_description: "NetApp ONTAP Manage NVME Namespace"
-version_added: "2.8"
-'''
-
-EXAMPLES = """
-
- - name: Create NVME Namespace
- na_ontap_nvme_namespace:
- state: present
- ostype: linux
- path: /vol/ansible/test
- size: 20
- vserver: "{{ vserver }}"
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
-
- - name: Create NVME Namespace (Idempotency)
- na_ontap_nvme_namespace:
- state: present
- ostype: linux
- path: /vol/ansible/test
- size: 20
- vserver: "{{ vserver }}"
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPNVMENamespace(object):
- """
- Class with NVME namespace methods
- """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- ostype=dict(required=False, type='str', choices=['windows', 'linux', 'vmware', 'xen', 'hyper_v']),
- path=dict(required=True, type='str'),
- size=dict(required=False, type='int')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[('state', 'present', ['ostype', 'size'])],
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_namespace(self):
- """
- Get current namespace details
- :return: dict if namespace exists, None otherwise
- """
- namespace_get = netapp_utils.zapi.NaElement('nvme-namespace-get-iter')
- query = {
- 'query': {
- 'nvme-namespace-info': {
- 'path': self.parameters['path'],
- 'vserver': self.parameters['vserver']
- }
- }
- }
- namespace_get.translate_struct(query)
- try:
- result = self.server.invoke_successfully(namespace_get, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching namespace info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- return result
- return None
-
- def create_namespace(self):
- """
- Create a NVME Namespace
- """
- options = {'path': self.parameters['path'],
- 'ostype': self.parameters['ostype'],
- 'size': self.parameters['size']
- }
- namespace_create = netapp_utils.zapi.NaElement('nvme-namespace-create')
- namespace_create.translate_struct(options)
- try:
- self.server.invoke_successfully(namespace_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating namespace for path %s: %s'
- % (self.parameters.get('path'), to_native(error)),
- exception=traceback.format_exc())
-
- def delete_namespace(self):
- """
- Delete a NVME Namespace
- """
- options = {'path': self.parameters['path']
- }
- namespace_delete = netapp_utils.zapi.NaElement.create_node_with_children('nvme-namespace-delete', **options)
- try:
- self.server.invoke_successfully(namespace_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting namespace for path %s: %s'
- % (self.parameters.get('path'), to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Apply action to NVME Namespace
- """
- netapp_utils.ems_log_event("na_ontap_nvme_namespace", self.server)
- current = self.get_namespace()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_namespace()
- elif cd_action == 'delete':
- self.delete_namespace()
-
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """Execute action"""
- community_obj = NetAppONTAPNVMENamespace()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_nvme_subsystem.py b/lib/ansible/modules/storage/netapp/na_ontap_nvme_subsystem.py
deleted file mode 100644
index 6de354dc09..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_nvme_subsystem.py
+++ /dev/null
@@ -1,355 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Create/Delete NVME subsystem
- - Associate(modify) host/map to NVME subsystem
- - NVMe service should be existing in the data vserver with NVMe protocol as a pre-requisite
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_nvme_subsystem
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified subsystem should exist or not.
- default: present
- vserver:
- description:
- - Name of the vserver to use.
- required: true
- subsystem:
- description:
- - Specifies the subsystem
- required: true
- ostype:
- description:
- - Specifies the ostype for initiators
- choices: ['windows', 'linux', 'vmware', 'xen', 'hyper_v']
- skip_host_check:
- description:
- - Skip host check
- - Required to delete an NVMe Subsystem with attached NVMe namespaces
- default: false
- type: bool
- skip_mapped_check:
- description:
- - Skip mapped namespace check
- - Required to delete an NVMe Subsystem with attached NVMe namespaces
- default: false
- type: bool
- hosts:
- description:
- - List of host NQNs (NVMe Qualification Name) associated to the controller.
- type: list
- paths:
- description:
- - List of Namespace paths to be associated with the subsystem.
- type: list
-short_description: "NetApp ONTAP Manage NVME Subsystem"
-version_added: "2.8"
-'''
-
-EXAMPLES = """
-
- - name: Create NVME Subsystem
- na_ontap_nvme_subsystem:
- state: present
- subsystem: test_sub
- vserver: test_dest
- ostype: linux
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete NVME Subsystem
- na_ontap_nvme_subsystem:
- state: absent
- subsystem: test_sub
- vserver: test_dest
- skip_host_check: True
- skip_mapped_check: True
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Associate NVME Subsystem host/map
- na_ontap_nvme_subsystem:
- state: present
- subsystem: "{{ subsystem }}"
- ostype: linux
- hosts: nqn.1992-08.com.netapp:sn.3017cfc1e2ba11e89c55005056b36338:subsystem.ansible
- paths: /vol/ansible/test,/vol/ansible/test1
- vserver: "{{ vserver }}"
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
-
- - name: Modify NVME subsystem map
- na_ontap_nvme_subsystem:
- state: present
- subsystem: test_sub
- vserver: test_dest
- skip_host_check: True
- skip_mapped_check: True
- paths: /vol/ansible/test
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPNVMESubsystem(object):
- """
- Class with NVME subsytem methods
- """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- subsystem=dict(required=True, type='str'),
- ostype=dict(required=False, type='str', choices=['windows', 'linux', 'vmware', 'xen', 'hyper_v']),
- skip_host_check=dict(required=False, type='bool', default=False),
- skip_mapped_check=dict(required=False, type='bool', default=False),
- hosts=dict(required=False, type='list'),
- paths=dict(required=False, type='list')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_subsystem(self):
- """
- Get current subsystem details
- :return: dict if subsystem exists, None otherwise
- """
- subsystem_get = netapp_utils.zapi.NaElement('nvme-subsystem-get-iter')
- query = {
- 'query': {
- 'nvme-subsytem-info': {
- 'subsystem': self.parameters.get('subsystem')
- }
- }
- }
- subsystem_get.translate_struct(query)
- try:
- result = self.server.invoke_successfully(subsystem_get, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching subsystem info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- return True
- return None
-
- def create_subsystem(self):
- """
- Create a NVME Subsystem
- """
- if self.parameters.get('ostype') is None:
- self.module.fail_json(msg="Error: Missing required parameter 'os_type' for creating subsystem")
- options = {'subsystem': self.parameters['subsystem'],
- 'ostype': self.parameters['ostype']
- }
- subsystem_create = netapp_utils.zapi.NaElement('nvme-subsystem-create')
- subsystem_create.translate_struct(options)
- try:
- self.server.invoke_successfully(subsystem_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating subsystem for %s: %s'
- % (self.parameters.get('subsystem'), to_native(error)),
- exception=traceback.format_exc())
-
- def delete_subsystem(self):
- """
- Delete a NVME subsystem
- """
- options = {'subsystem': self.parameters['subsystem'],
- 'skip-host-check': 'true' if self.parameters.get('skip_host_check') else 'false',
- 'skip-mapped-check': 'true' if self.parameters.get('skip_mapped_check') else 'false',
- }
- subsystem_delete = netapp_utils.zapi.NaElement.create_node_with_children('nvme-subsystem-delete', **options)
- try:
- self.server.invoke_successfully(subsystem_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting subsystem for %s: %s'
- % (self.parameters.get('subsystem'), to_native(error)),
- exception=traceback.format_exc())
-
- def get_subsystem_host_map(self, type):
- """
- Get current subsystem host details
- :return: list if host exists, None otherwise
- """
- if type == 'hosts':
- zapi_get, zapi_info, zapi_type = 'nvme-subsystem-host-get-iter', 'nvme-target-subsystem-host-info',\
- 'host-nqn'
- elif type == 'paths':
- zapi_get, zapi_info, zapi_type = 'nvme-subsystem-map-get-iter', 'nvme-target-subsystem-map-info', 'path'
- subsystem_get = netapp_utils.zapi.NaElement(zapi_get)
- query = {
- 'query': {
- zapi_info: {
- 'subsystem': self.parameters.get('subsystem')
- }
- }
- }
- subsystem_get.translate_struct(query)
- try:
- result = self.server.invoke_successfully(subsystem_get, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching subsystem info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- attrs_list = result.get_child_by_name('attributes-list')
- return_list = []
- for item in attrs_list.get_children():
- return_list.append(item[zapi_type])
- return {type: return_list}
- return None
-
- def add_subsystem_host_map(self, data, type):
- """
- Add a NVME Subsystem host/map
- :param: data: list of hosts/paths to be added
- :param: type: hosts/paths
- """
- if type == 'hosts':
- zapi_add, zapi_type = 'nvme-subsystem-host-add', 'host-nqn'
- elif type == 'paths':
- zapi_add, zapi_type = 'nvme-subsystem-map-add', 'path'
-
- for item in data:
- options = {'subsystem': self.parameters['subsystem'],
- zapi_type: item
- }
- subsystem_add = netapp_utils.zapi.NaElement.create_node_with_children(zapi_add, **options)
- try:
- self.server.invoke_successfully(subsystem_add, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error adding %s for subsystem %s: %s'
- % (item, self.parameters.get('subsystem'), to_native(error)),
- exception=traceback.format_exc())
-
- def remove_subsystem_host_map(self, data, type):
- """
- Remove a NVME Subsystem host/map
- :param: data: list of hosts/paths to be added
- :param: type: hosts/paths
- """
- if type == 'hosts':
- zapi_remove, zapi_type = 'nvme-subsystem-host-remove', 'host-nqn'
- elif type == 'paths':
- zapi_remove, zapi_type = 'nvme-subsystem-map-remove', 'path'
-
- for item in data:
- options = {'subsystem': self.parameters['subsystem'],
- zapi_type: item
- }
- subsystem_remove = netapp_utils.zapi.NaElement.create_node_with_children(zapi_remove, **options)
- try:
- self.server.invoke_successfully(subsystem_remove, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error removing %s for subsystem %s: %s'
- % (item, self.parameters.get('subsystem'), to_native(error)),
- exception=traceback.format_exc())
-
- def associate_host_map(self, types):
- """
- Check if there are hosts or paths to be associated with the subsystem
- """
- action_add_dict = {}
- action_remove_dict = {}
- for type in types:
- if self.parameters.get(type):
- current = self.get_subsystem_host_map(type)
- if current:
- add_items = self.na_helper.\
- get_modified_attributes(current, self.parameters, get_list_diff=True).get(type)
- remove_items = [item for item in current[type] if item not in self.parameters.get(type)]
- else:
- add_items = self.parameters[type]
- remove_items = {}
- if add_items:
- action_add_dict[type] = add_items
- self.na_helper.changed = True
- if remove_items:
- action_remove_dict[type] = remove_items
- self.na_helper.changed = True
- return action_add_dict, action_remove_dict
-
- def modify_host_map(self, add_host_map, remove_host_map):
- for type, data in add_host_map.items():
- self.add_subsystem_host_map(data, type)
- for type, data in remove_host_map.items():
- self.remove_subsystem_host_map(data, type)
-
- def apply(self):
- """
- Apply action to NVME subsystem
- """
- netapp_utils.ems_log_event("na_ontap_nvme_subsystem", self.server)
- types = ['hosts', 'paths']
- current = self.get_subsystem()
- add_host_map, remove_host_map = dict(), dict()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action != 'delete' and self.parameters['state'] == 'present':
- add_host_map, remove_host_map = self.associate_host_map(types)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_subsystem()
- self.modify_host_map(add_host_map, remove_host_map)
- elif cd_action == 'delete':
- self.delete_subsystem()
- elif cd_action is None:
- self.modify_host_map(add_host_map, remove_host_map)
-
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """Execute action"""
- community_obj = NetAppONTAPNVMESubsystem()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_object_store.py b/lib/ansible/modules/storage/netapp/na_ontap_object_store.py
deleted file mode 100644
index bb5bb1ee3a..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_object_store.py
+++ /dev/null
@@ -1,237 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_object_store
-short_description: NetApp ONTAP manage object store config.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create or delete object store config on ONTAP.
-
-options:
-
- state:
- description:
- - Whether the specified object store config should exist or not.
- choices: ['present', 'absent']
- default: 'present'
- type: str
-
- name:
- required: true
- description:
- - The name of the object store config to manage.
- type: str
-
- provider_type:
- required: false
- description:
- - The name of the object store config provider.
- type: str
-
- server:
- required: false
- description:
- - Fully qualified domain name of the object store config.
- type: str
-
- container:
- required: false
- description:
- - Data bucket/container name used in S3 requests.
- type: str
-
- access_key:
- required: false
- description:
- - Access key ID for AWS_S3 and SGWS provider types.
- type: str
-
- secret_password:
- required: false
- description:
- - Secret access key for AWS_S3 and SGWS provider types.
- type: str
-'''
-
-EXAMPLES = """
-- name: object store Create
- na_ontap_object_store:
- state: present
- name: ansible
- provider_type: SGWS
- server: abc
- container: abc
- access_key: s3.amazonaws.com
- secret_password: abc
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
-
-- name: object store Create
- na_ontap_object_store:
- state: absent
- name: ansible
- hostname: "{{ hostname }}"
- username: "{{ username }}"
- password: "{{ password }}"
-"""
-
-RETURN = """
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapObjectStoreConfig(object):
- ''' object initialize and class methods '''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- name=dict(required=True, type='str'),
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- provider_type=dict(required=False, type='str'),
- server=dict(required=False, type='str'),
- container=dict(required=False, type='str'),
- access_key=dict(required=False, type='str'),
- secret_password=dict(required=False, type='str', no_log=True)
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def get_aggr_object_store(self):
- """
- Fetch details if object store config exists.
- :return:
- Dictionary of current details if object store config found
- None if object store config is not found
- """
- aggr_object_store_get_iter = netapp_utils.zapi.NaElement.create_node_with_children(
- 'aggr-object-store-config-get', **{'object-store-name': self.parameters['name']})
- result = None
- try:
- result = self.server.invoke_successfully(aggr_object_store_get_iter, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- # Error 15661 denotes an object store not being found.
- if to_native(error.code) == "15661":
- pass
- else:
- self.module.fail_json(msg=to_native(error), exception=traceback.format_exc())
- return result
-
- def create_aggr_object_store(self):
- """
- Create aggregate object store config
- :return: None
- """
- required_keys = set(['provider_type', 'server', 'container', 'access_key'])
- if not required_keys.issubset(set(self.parameters.keys())):
- self.module.fail_json(msg='Error provisioning object store %s: one of the following parameters are missing '
- '%s' % (self.parameters['name'], ', '.join(required_keys)))
- options = {'object-store-name': self.parameters['name'],
- 'provider-type': self.parameters['provider_type'],
- 'server': self.parameters['server'],
- 's3-name': self.parameters['container'],
- 'access-key': self.parameters['access_key']}
- if self.parameters.get('secret_password'):
- options['secret-password'] = self.parameters['secret_password']
- object_store_create = netapp_utils.zapi.NaElement.create_node_with_children('aggr-object-store-config-create', **options)
-
- try:
- self.server.invoke_successfully(object_store_create, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error provisioning object store config %s: %s"
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_aggr_object_store(self):
- """
- Delete aggregate object store config
- :return: None
- """
- object_store_destroy = netapp_utils.zapi.NaElement.create_node_with_children(
- 'aggr-object-store-config-delete', **{'object-store-name': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(object_store_destroy,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error removing object store config %s: %s" %
- (self.parameters['name'], to_native(error)), exception=traceback.format_exc())
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
- def apply(self):
- """
- Apply action to the object store config
- :return: None
- """
- self.asup_log_for_cserver("na_ontap_object_store_config")
- current = self.get_aggr_object_store()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_aggr_object_store()
- elif cd_action == 'delete':
- self.delete_aggr_object_store()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Create Object Store Config class instance and invoke apply
- :return: None
- """
- obj_store = NetAppOntapObjectStoreConfig()
- obj_store.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_ports.py b/lib/ansible/modules/storage/netapp/na_ontap_ports.py
deleted file mode 100644
index 4ec11f5260..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_ports.py
+++ /dev/null
@@ -1,380 +0,0 @@
-#!/usr/bin/python
-''' This is an Ansible module for ONTAP to manage ports for various resources.
-
- (c) 2019, NetApp, Inc
- # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-'''
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'
-}
-
-DOCUMENTATION = '''
-
-module: na_ontap_ports
-short_description: NetApp ONTAP add/remove ports
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - Add or remove ports for broadcast domain and portset.
-
-options:
- state:
- description:
- - Whether the specified port should be added or removed.
- choices: ['present', 'absent']
- default: present
- type: str
-
- vserver:
- description:
- - Name of the SVM.
- - Specify this option when operating on portset.
- type: str
-
- names:
- description:
- - List of ports.
- type: list
- required: true
-
- resource_name:
- description:
- - name of the portset or broadcast domain.
- type: str
- required: true
-
- resource_type:
- description:
- - type of the resource to add a port to or remove a port from.
- choices: ['broadcast_domain', 'portset']
- required: true
- type: str
-
- ipspace:
- description:
- - Specify the required ipspace for the broadcast domain.
- - A domain ipspace can not be modified after the domain has been created.
- type: str
-
- portset_type:
- description:
- - Protocols accepted for portset.
- choices: ['fcp', 'iscsi', 'mixed']
- type: str
-
-'''
-
-EXAMPLES = '''
-
- - name: broadcast domain remove port
- tags:
- - remove
- na_ontap_ports:
- state: absent
- names: test-vsim1:e0d-1,test-vsim1:e0d-2
- resource_type: broadcast_domain
- resource_name: ansible_domain
- hostname: "{{ hostname }}"
- username: user
- password: password
- https: False
-
- - name: broadcast domain add port
- tags:
- - add
- na_ontap_ports:
- state: present
- names: test-vsim1:e0d-1,test-vsim1:e0d-2
- resource_type: broadcast_domain
- resource_name: ansible_domain
- ipspace: Default
- hostname: "{{ hostname }}"
- username: user
- password: password
- https: False
-
- - name: portset remove port
- tags:
- - remove
- na_ontap_ports:
- state: absent
- names: lif_2
- resource_type: portset
- resource_name: portset_1
- vserver: "{{ vserver }}"
- hostname: "{{ hostname }}"
- username: user
- password: password
- https: False
-
- - name: portset add port
- tags:
- - add
- na_ontap_ports:
- state: present
- names: lif_2
- resource_type: portset
- resource_name: portset_1
- portset_type: iscsi
- vserver: "{{ vserver }}"
- hostname: "{{ hostname }}"
- username: user
- password: password
- https: False
-
-'''
-
-RETURN = '''
-'''
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapPorts(object):
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- vserver=dict(required=False, type='str'),
- names=dict(required=True, type='list'),
- resource_name=dict(required=True, type='str'),
- resource_type=dict(required=True, type='str', choices=['broadcast_domain', 'portset']),
- ipspace=dict(required=False, type='str'),
- portset_type=dict(required=False, type='str', choices=['fcp', 'iscsi', 'mixed']),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('resource_type', 'portset', ['vserver']),
- ],
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- if self.parameters['resource_type'] == 'broadcast_domain':
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- elif self.parameters['resource_type'] == 'portset':
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=self.parameters['vserver'])
-
- def add_broadcast_domain_ports(self, ports):
- """
- Add broadcast domain ports
- :param: ports to be added.
- """
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-add-ports')
- domain_obj.add_new_child("broadcast-domain", self.parameters['resource_name'])
- if self.parameters.get('ipspace'):
- domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
- ports_obj = netapp_utils.zapi.NaElement('ports')
- domain_obj.add_child_elem(ports_obj)
- for port in ports:
- ports_obj.add_new_child('net-qualified-port-name', port)
- try:
- self.server.invoke_successfully(domain_obj, True)
- return True
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error adding port for broadcast domain %s: %s' %
- (self.parameters['resource_name'], to_native(error)),
- exception=traceback.format_exc())
-
- def remove_broadcast_domain_ports(self, ports):
- """
- Deletes broadcast domain ports
- :param: ports to be removed.
- """
- domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-remove-ports')
- domain_obj.add_new_child("broadcast-domain", self.parameters['resource_name'])
- if self.parameters.get('ipspace'):
- domain_obj.add_new_child("ipspace", self.parameters['ipspace'])
- ports_obj = netapp_utils.zapi.NaElement('ports')
- domain_obj.add_child_elem(ports_obj)
- for port in ports:
- ports_obj.add_new_child('net-qualified-port-name', port)
- try:
- self.server.invoke_successfully(domain_obj, True)
- return True
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error removing port for broadcast domain %s: %s' %
- (self.parameters['resource_name'], to_native(error)),
- exception=traceback.format_exc())
-
- def get_broadcast_domain_ports(self):
- """
- Return details about the broadcast domain ports.
- :return: Details about the broadcast domain ports. [] if not found.
- :rtype: list
- """
- domain_get_iter = netapp_utils.zapi.NaElement('net-port-broadcast-domain-get-iter')
- broadcast_domain_info = netapp_utils.zapi.NaElement('net-port-broadcast-domain-info')
- broadcast_domain_info.add_new_child('broadcast-domain', self.parameters['resource_name'])
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(broadcast_domain_info)
- domain_get_iter.add_child_elem(query)
- result = self.server.invoke_successfully(domain_get_iter, True)
- ports = []
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
- domain_info = result.get_child_by_name('attributes-list').get_child_by_name('net-port-broadcast-domain-info')
- domain_ports = domain_info.get_child_by_name('ports')
- if domain_ports is not None:
- ports = [port.get_child_content('port') for port in domain_ports.get_children()]
- return ports
-
- def remove_portset_ports(self, port):
- """
- Removes all existing ports from portset
- :return: None
- """
- options = {'portset-name': self.parameters['resource_name'],
- 'portset-port-name': port.strip()}
-
- portset_modify = netapp_utils.zapi.NaElement.create_node_with_children('portset-remove', **options)
-
- try:
- self.server.invoke_successfully(portset_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error removing port in portset %s: %s' %
- (self.parameters['resource_name'], to_native(error)), exception=traceback.format_exc())
-
- def add_portset_ports(self, port):
- """
- Add the list of ports to portset
- :return: None
- """
- options = {'portset-name': self.parameters['resource_name'],
- 'portset-port-name': port.strip()}
-
- portset_modify = netapp_utils.zapi.NaElement.create_node_with_children('portset-add', **options)
-
- try:
- self.server.invoke_successfully(portset_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error adding port in portset %s: %s' %
- (self.parameters['resource_name'], to_native(error)), exception=traceback.format_exc())
-
- def portset_get_iter(self):
- """
- Compose NaElement object to query current portset using vserver, portset-name and portset-type parameters
- :return: NaElement object for portset-get-iter with query
- """
- portset_get = netapp_utils.zapi.NaElement('portset-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- portset_info = netapp_utils.zapi.NaElement('portset-info')
- portset_info.add_new_child('vserver', self.parameters['vserver'])
- portset_info.add_new_child('portset-name', self.parameters['resource_name'])
- if self.parameters.get('portset_type'):
- portset_info.add_new_child('portset-type', self.parameters['portset_type'])
- query.add_child_elem(portset_info)
- portset_get.add_child_elem(query)
- return portset_get
-
- def portset_get(self):
- """
- Get current portset info
- :return: List of current ports if query successful, else return []
- """
- portset_get_iter = self.portset_get_iter()
- result, ports = None, []
- try:
- result = self.server.invoke_successfully(portset_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching portset %s: %s'
- % (self.parameters['resource_name'], to_native(error)),
- exception=traceback.format_exc())
- # return portset details
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) > 0:
- portset_get_info = result.get_child_by_name('attributes-list').get_child_by_name('portset-info')
- if int(portset_get_info.get_child_content('portset-port-total')) > 0:
- port_info = portset_get_info.get_child_by_name('portset-port-info')
- ports = [port.get_content() for port in port_info.get_children()]
- return ports
-
- def modify_broadcast_domain_ports(self):
- """
- compare current and desire ports. Call add or remove ports methods if needed.
- :return: None.
- """
- current_ports = self.get_broadcast_domain_ports()
- cd_ports = self.parameters['names']
- if self.parameters['state'] == 'present':
- ports_to_add = [port for port in cd_ports if port not in current_ports]
- if len(ports_to_add) > 0:
- self.add_broadcast_domain_ports(ports_to_add)
- self.na_helper.changed = True
-
- if self.parameters['state'] == 'absent':
- ports_to_remove = [port for port in cd_ports if port in current_ports]
- if len(ports_to_remove) > 0:
- self.remove_broadcast_domain_ports(ports_to_remove)
- self.na_helper.changed = True
-
- def modify_portset_ports(self):
- current_ports = self.portset_get()
- cd_ports = self.parameters['names']
- if self.parameters['state'] == 'present':
- ports_to_add = [port for port in cd_ports if port not in current_ports]
- if len(ports_to_add) > 0:
- for port in ports_to_add:
- self.add_portset_ports(port)
- self.na_helper.changed = True
-
- if self.parameters['state'] == 'absent':
- ports_to_remove = [port for port in cd_ports if port in current_ports]
- if len(ports_to_remove) > 0:
- for port in ports_to_remove:
- self.remove_portset_ports(port)
- self.na_helper.changed = True
-
- def apply(self):
- self.asup_log_for_cserver("na_ontap_ports")
- if self.parameters['resource_type'] == 'broadcast_domain':
- self.modify_broadcast_domain_ports()
- elif self.parameters['resource_type'] == 'portset':
- self.modify_portset_ports()
- self.module.exit_json(changed=self.na_helper.changed)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
-
-def main():
- portset_obj = NetAppOntapPorts()
- portset_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_portset.py b/lib/ansible/modules/storage/netapp/na_ontap_portset.py
deleted file mode 100644
index 2cb2d7b289..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_portset.py
+++ /dev/null
@@ -1,278 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
-short_description: NetApp ONTAP Create/Delete portset
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Create/Delete ONTAP portset, modify ports in a portset.
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_portset
-options:
- state:
- description:
- - If you want to create a portset.
- default: present
- vserver:
- required: true
- description:
- - Name of the SVM.
- name:
- required: true
- description:
- - Name of the port set to create.
- type:
- description:
- - Required for create.
- - Protocols accepted for this portset.
- choices: ['fcp', 'iscsi', 'mixed']
- force:
- description:
- - If 'false' or not specified, the request will fail if there are any igroups bound to this portset.
- - If 'true', forcibly destroy the portset, even if there are existing igroup bindings.
- type: bool
- default: False
- ports:
- description:
- - Specify the ports associated with this portset. Should be comma separated.
- - It represents the expected state of a list of ports at any time, and replaces the current value of ports.
- - Adds a port if it is specified in expected state but not in current state.
- - Deletes a port if it is in current state but not in expected state.
-version_added: "2.8"
-
-'''
-
-EXAMPLES = """
- - name: Create Portset
- na_ontap_portset:
- state: present
- vserver: vserver_name
- name: portset_name
- ports: a1
- type: "{{ protocol type }}"
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
- hostname: "{{ netapp hostname }}"
-
- - name: Modify ports in portset
- na_ontap_portset:
- state: present
- vserver: vserver_name
- name: portset_name
- ports: a1,a2
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
- hostname: "{{ netapp hostname }}"
-
- - name: Delete Portset
- na_ontap_portset:
- state: absent
- vserver: vserver_name
- name: portset_name
- force: True
- type: "{{ protocol type }}"
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
- hostname: "{{ netapp hostname }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPPortset(object):
- """
- Methods to create or delete portset
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, default='present'),
- vserver=dict(required=True, type='str'),
- name=dict(required=True, type='str'),
- type=dict(required=False, type='str', choices=[
- 'fcp', 'iscsi', 'mixed']),
- force=dict(required=False, type='bool', default=False),
- ports=dict(required=False, type='list')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=self.parameters['vserver'])
-
- def portset_get_iter(self):
- """
- Compose NaElement object to query current portset using vserver, portset-name and portset-type parameters
- :return: NaElement object for portset-get-iter with query
- """
- portset_get = netapp_utils.zapi.NaElement('portset-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- portset_info = netapp_utils.zapi.NaElement('portset-info')
- portset_info.add_new_child('vserver', self.parameters['vserver'])
- portset_info.add_new_child('portset-name', self.parameters['name'])
- if self.parameters.get('type'):
- portset_info.add_new_child('portset-type', self.parameters['type'])
- query.add_child_elem(portset_info)
- portset_get.add_child_elem(query)
- return portset_get
-
- def portset_get(self):
- """
- Get current portset info
- :return: Dictionary of current portset details if query successful, else return None
- """
- portset_get_iter = self.portset_get_iter()
- result, portset_info = None, dict()
- try:
- result = self.server.invoke_successfully(portset_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching portset %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- # return portset details
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) > 0:
- portset_get_info = result.get_child_by_name('attributes-list').get_child_by_name('portset-info')
- if int(portset_get_info.get_child_content('portset-port-total')) > 0:
- ports = portset_get_info.get_child_by_name('portset-port-info')
- portset_info['ports'] = [port.get_content() for port in ports.get_children()]
- else:
- portset_info['ports'] = []
- return portset_info
- return None
-
- def create_portset(self):
- """
- Create a portset
- """
- if self.parameters.get('type') is None:
- self.module.fail_json(msg='Error: Missing required parameter for create (type)')
- portset_info = netapp_utils.zapi.NaElement("portset-create")
- portset_info.add_new_child("portset-name", self.parameters['name'])
- portset_info.add_new_child("portset-type", self.parameters['type'])
- try:
- self.server.invoke_successfully(
- portset_info, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error creating portset %s: %s" %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_portset(self):
- """
- Delete a portset
- """
- portset_info = netapp_utils.zapi.NaElement("portset-destroy")
- portset_info.add_new_child("portset-name", self.parameters['name'])
- if self.parameters.get('force'):
- portset_info.add_new_child("force", str(self.parameters['force']))
- try:
- self.server.invoke_successfully(
- portset_info, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error deleting portset %s: %s" %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def remove_ports(self, ports):
- """
- Removes all existing ports from portset
- :return: None
- """
- for port in ports:
- self.modify_port(port, 'portset-remove', 'removing')
-
- def add_ports(self):
- """
- Add the list of ports to portset
- :return: None
- """
- # don't add if ports is empty string
- if self.parameters.get('ports') == [''] or self.parameters.get('ports') is None:
- return
- for port in self.parameters['ports']:
- self.modify_port(port, 'portset-add', 'adding')
-
- def modify_port(self, port, zapi, action):
- """
- Add or remove an port to/from a portset
- """
- port.strip() # remove leading spaces if any (eg: if user types a space after comma in initiators list)
- options = {'portset-name': self.parameters['name'],
- 'portset-port-name': port}
-
- portset_modify = netapp_utils.zapi.NaElement.create_node_with_children(zapi, **options)
-
- try:
- self.server.invoke_successfully(portset_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error %s port in portset %s: %s' % (action, self.parameters['name'],
- to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Applies action from playbook
- """
- netapp_utils.ems_log_event("na_ontap_autosupport", self.server)
- current, modify = self.portset_get(), None
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action is None and self.parameters['state'] == 'present':
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
-
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_portset()
- self.add_ports()
- elif cd_action == 'delete':
- self.delete_portset()
- elif modify:
- self.remove_ports(current['ports'])
- self.add_ports()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Execute action from playbook
- """
- portset_obj = NetAppONTAPPortset()
- portset_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_qos_adaptive_policy_group.py b/lib/ansible/modules/storage/netapp/na_ontap_qos_adaptive_policy_group.py
deleted file mode 100644
index 1a5b611c1c..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_qos_adaptive_policy_group.py
+++ /dev/null
@@ -1,335 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_qos_adaptive_policy_group
-short_description: NetApp ONTAP Adaptive Quality of Service policy group.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: NetApp Ansible Team (@joshedmonds) <ng-ansibleteam@netapp.com>
-
-description:
- - Create, destroy, modify, or rename an Adaptive QoS policy group on NetApp ONTAP. Module is based on the standard QoS policy group module.
-
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified policy group should exist or not.
- default: 'present'
- type: str
-
- name:
- description:
- - The name of the policy group to manage.
- type: str
- required: true
-
- vserver:
- description:
- - Name of the vserver to use.
- type: str
- required: true
-
- from_name:
- description:
- - Name of the existing policy group to be renamed to name.
- type: str
-
- absolute_min_iops:
- description:
- - Absolute minimum IOPS defined by this policy.
- type: str
-
- expected_iops:
- description:
- - Minimum expected IOPS defined by this policy.
- type: str
-
- peak_iops:
- description:
- - Maximum possible IOPS per allocated or used TB|GB.
- type: str
-
- peak_iops_allocation:
- choices: ['allocated_space', 'used_space']
- description:
- - Whether peak_iops is specified by allocated or used space.
- default: 'used_space'
- type: str
-
- force:
- type: bool
- default: False
- description:
- - Setting to 'true' forces the deletion of the workloads associated with the policy group along with the policy group.
-'''
-
-EXAMPLES = """
- - name: create adaptive qos policy group
- na_ontap_qos_adaptive_policy_group:
- state: present
- name: aq_policy_1
- vserver: policy_vserver
- absolute_min_iops: 70IOPS
- expected_iops: 100IOPS/TB
- peak_iops: 250IOPS/TB
- peak_iops_allocation: allocated_space
- hostname: 10.193.78.30
- username: admin
- password: netapp1!
-
- - name: modify adaptive qos policy group expected iops
- na_ontap_qos_adaptive_policy_group:
- state: present
- name: aq_policy_1
- vserver: policy_vserver
- absolute_min_iops: 70IOPS
- expected_iops: 125IOPS/TB
- peak_iops: 250IOPS/TB
- peak_iops_allocation: allocated_space
- hostname: 10.193.78.30
- username: admin
- password: netapp1!
-
- - name: modify adaptive qos policy group peak iops allocation
- na_ontap_qos_adaptive_policy_group:
- state: present
- name: aq_policy_1
- vserver: policy_vserver
- absolute_min_iops: 70IOPS
- expected_iops: 125IOPS/TB
- peak_iops: 250IOPS/TB
- peak_iops_allocation: used_space
- hostname: 10.193.78.30
- username: admin
- password: netapp1!
-
- - name: delete qos policy group
- na_ontap_qos_adaptive_policy_group:
- state: absent
- name: aq_policy_1
- vserver: policy_vserver
- hostname: 10.193.78.30
- username: admin
- password: netapp1!
-
-"""
-
-RETURN = """
-"""
-
-import traceback
-
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapAdaptiveQosPolicyGroup(object):
- """
- Create, delete, modify and rename a policy group.
- """
- def __init__(self):
- """
- Initialize the Ontap qos policy group class.
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- from_name=dict(required=False, type='str'),
- vserver=dict(required=True, type='str'),
- absolute_min_iops=dict(required=False, type='str'),
- expected_iops=dict(required=False, type='str'),
- peak_iops=dict(required=False, type='str'),
- peak_iops_allocation=dict(choices=['allocated_space', 'used_space'], default='used_space'),
- force=dict(required=False, type='bool', default=False)
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module)
-
- def get_policy_group(self, policy_group_name=None):
- """
- Return details of a policy group.
- :param policy_group_name: policy group name
- :return: policy group details.
- :rtype: dict.
- """
- if policy_group_name is None:
- policy_group_name = self.parameters['name']
- policy_group_get_iter = netapp_utils.zapi.NaElement('qos-adaptive-policy-group-get-iter')
- policy_group_info = netapp_utils.zapi.NaElement('qos-adaptive-policy-group-info')
- policy_group_info.add_new_child('policy-group', policy_group_name)
- policy_group_info.add_new_child('vserver', self.parameters['vserver'])
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(policy_group_info)
- policy_group_get_iter.add_child_elem(query)
- result = self.server.invoke_successfully(policy_group_get_iter, True)
- policy_group_detail = None
-
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) == 1:
- policy_info = result.get_child_by_name('attributes-list').get_child_by_name('qos-adaptive-policy-group-info')
-
- policy_group_detail = {
- 'name': policy_info.get_child_content('policy-group'),
- 'vserver': policy_info.get_child_content('vserver'),
- 'absolute_min_iops': policy_info.get_child_content('absolute-min-iops'),
- 'expected_iops': policy_info.get_child_content('expected-iops'),
- 'peak_iops': policy_info.get_child_content('peak-iops'),
- 'peak_iops_allocation': policy_info.get_child_content('peak-iops-allocation')
- }
- return policy_group_detail
-
- def create_policy_group(self):
- """
- create a policy group name.
- """
- policy_group = netapp_utils.zapi.NaElement('qos-adaptive-policy-group-create')
- policy_group.add_new_child('policy-group', self.parameters['name'])
- policy_group.add_new_child('vserver', self.parameters['vserver'])
- if self.parameters.get('absolute_min_iops'):
- policy_group.add_new_child('absolute-min-iops', self.parameters['absolute_min_iops'])
- if self.parameters.get('expected_iops'):
- policy_group.add_new_child('expected-iops', self.parameters['expected_iops'])
- if self.parameters.get('peak_iops'):
- policy_group.add_new_child('peak-iops', self.parameters['peak_iops'])
- if self.parameters.get('peak_iops_allocation'):
- policy_group.add_new_child('peak-iops-allocation', self.parameters['peak_iops_allocation'])
- try:
- self.server.invoke_successfully(policy_group, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating adaptive qos policy group %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_policy_group(self, policy_group=None):
- """
- delete an existing policy group.
- :param policy_group: policy group name.
- """
- if policy_group is None:
- policy_group = self.parameters['name']
- policy_group_obj = netapp_utils.zapi.NaElement('qos-adaptive-policy-group-delete')
- policy_group_obj.add_new_child('policy-group', policy_group)
- if self.parameters.get('force'):
- policy_group_obj.add_new_child('force', str(self.parameters['force']))
- try:
- self.server.invoke_successfully(policy_group_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting adaptive qos policy group %s: %s' %
- (policy_group, to_native(error)),
- exception=traceback.format_exc())
-
- def modify_policy_group(self):
- """
- Modify policy group.
- """
- policy_group_obj = netapp_utils.zapi.NaElement('qos-adaptive-policy-group-modify')
- policy_group_obj.add_new_child('policy-group', self.parameters['name'])
- if self.parameters.get('absolute_min_iops'):
- policy_group_obj.add_new_child('absolute-min-iops', self.parameters['absolute_min_iops'])
- if self.parameters.get('expected_iops'):
- policy_group_obj.add_new_child('expected-iops', self.parameters['expected_iops'])
- if self.parameters.get('peak_iops'):
- policy_group_obj.add_new_child('peak-iops', self.parameters['peak_iops'])
- if self.parameters.get('peak_iops_allocation'):
- policy_group_obj.add_new_child('peak-iops-allocation', self.parameters['peak_iops_allocation'])
- try:
- self.server.invoke_successfully(policy_group_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying adaptive qos policy group %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def rename_policy_group(self):
- """
- Rename policy group name.
- """
- rename_obj = netapp_utils.zapi.NaElement('qos-adaptive-policy-group-rename')
- rename_obj.add_new_child('new-name', self.parameters['name'])
- rename_obj.add_new_child('policy-group-name', self.parameters['from_name'])
- try:
- self.server.invoke_successfully(rename_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error renaming adaptive qos policy group %s: %s' %
- (self.parameters['from_name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_helper(self, modify):
- """
- helper method to modify policy group.
- :param modify: modified attributes.
- """
- for attribute in modify.keys():
- if attribute in ['absolute_min_iops', 'expected_iops', 'peak_iops', 'peak_iops_allocation']:
- self.modify_policy_group()
-
- def apply(self):
- """
- Run module based on playbook
- """
- self.autosupport_log("na_ontap_qos_policy_group")
- current = self.get_policy_group()
- rename, cd_action = None, None
- if self.parameters.get('from_name'):
- rename = self.na_helper.is_rename_action(self.get_policy_group(self.parameters['from_name']), current)
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_policy_group()
- if cd_action == 'create':
- self.create_policy_group()
- elif cd_action == 'delete':
- self.delete_policy_group()
- elif modify:
- self.modify_helper(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
- def autosupport_log(self, event_name):
- """
- Create a log event against the provided vserver
- """
- server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
- netapp_utils.ems_log_event(event_name, server)
-
-
-def main():
- '''Apply vserver operations from playbook'''
- qos_policy_group = NetAppOntapAdaptiveQosPolicyGroup()
- qos_policy_group.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_qos_policy_group.py b/lib/ansible/modules/storage/netapp/na_ontap_qos_policy_group.py
deleted file mode 100644
index ed925fb30c..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_qos_policy_group.py
+++ /dev/null
@@ -1,290 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_qos_policy_group
-short_description: NetApp ONTAP manage policy group in Quality of Service.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - Create, destroy, modify, or rename QoS policy group on NetApp ONTAP.
-
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified policy group should exist or not.
- default: 'present'
-
- name:
- description:
- - The name of the policy group to manage.
-
- vserver:
- description:
- - Name of the vserver to use.
-
- from_name:
- description:
- - Name of the existing policy group to be renamed to name.
-
- max_throughput:
- description:
- - Maximum throughput defined by this policy.
-
- min_throughput:
- description:
- - Minimum throughput defined by this policy.
-
- force:
- type: bool
- default: False
- description:
- - Setting to 'true' forces the deletion of the workloads associated with the policy group along with the policy group.
-'''
-
-EXAMPLES = """
- - name: create qos policy group
- na_ontap_qos_policy_group:
- state: present
- name: policy_1
- vserver: policy_vserver
- max_throughput: 800KB/s,800iops
- min_throughput: 100iops
- hostname: 10.193.78.30
- username: admin
- password: netapp1!
-
- - name: modify qos policy group max throughput
- na_ontap_qos_policy_group:
- state: present
- name: policy_1
- vserver: policy_vserver
- max_throughput: 900KB/s,800iops
- min_throughput: 100iops
- hostname: 10.193.78.30
- username: admin
- password: netapp1!
-
- - name: delete qos policy group
- na_ontap_qos_policy_group:
- state: absent
- name: policy_1
- vserver: policy_vserver
- hostname: 10.193.78.30
- username: admin
- password: netapp1!
-
-"""
-
-RETURN = """
-"""
-
-import traceback
-
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapQosPolicyGroup(object):
- """
- Create, delete, modify and rename a policy group.
- """
- def __init__(self):
- """
- Initialize the Ontap qos policy group class.
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- from_name=dict(required=False, type='str'),
- vserver=dict(required=True, type='str'),
- max_throughput=dict(required=False, type='str'),
- min_throughput=dict(required=False, type='str'),
- force=dict(required=False, type='bool', default=False)
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module)
-
- def get_policy_group(self, policy_group_name=None):
- """
- Return details of a policy group.
- :param policy_group_name: policy group name
- :return: policy group details.
- :rtype: dict.
- """
- if policy_group_name is None:
- policy_group_name = self.parameters['name']
- policy_group_get_iter = netapp_utils.zapi.NaElement('qos-policy-group-get-iter')
- policy_group_info = netapp_utils.zapi.NaElement('qos-policy-group-info')
- policy_group_info.add_new_child('policy-group', policy_group_name)
- policy_group_info.add_new_child('vserver', self.parameters['vserver'])
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(policy_group_info)
- policy_group_get_iter.add_child_elem(query)
- result = self.server.invoke_successfully(policy_group_get_iter, True)
- policy_group_detail = None
-
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) == 1:
- policy_info = result.get_child_by_name('attributes-list').get_child_by_name('qos-policy-group-info')
-
- policy_group_detail = {
- 'name': policy_info.get_child_content('policy-group'),
- 'vserver': policy_info.get_child_content('vserver'),
- 'max_throughput': policy_info.get_child_content('max-throughput'),
- 'min_throughput': policy_info.get_child_content('min-throughput')
- }
- return policy_group_detail
-
- def create_policy_group(self):
- """
- create a policy group name.
- """
- policy_group = netapp_utils.zapi.NaElement('qos-policy-group-create')
- policy_group.add_new_child('policy-group', self.parameters['name'])
- policy_group.add_new_child('vserver', self.parameters['vserver'])
- if self.parameters.get('max_throughput'):
- policy_group.add_new_child('max-throughput', self.parameters['max_throughput'])
- if self.parameters.get('min_throughput'):
- policy_group.add_new_child('min-throughput', self.parameters['min_throughput'])
- try:
- self.server.invoke_successfully(policy_group, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating qos policy group %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_policy_group(self, policy_group=None):
- """
- delete an existing policy group.
- :param policy_group: policy group name.
- """
- if policy_group is None:
- policy_group = self.parameters['name']
- policy_group_obj = netapp_utils.zapi.NaElement('qos-policy-group-delete')
- policy_group_obj.add_new_child('policy-group', policy_group)
- if self.parameters.get('force'):
- policy_group_obj.add_new_child('force', str(self.parameters['force']))
- try:
- self.server.invoke_successfully(policy_group_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting qos policy group %s: %s' %
- (policy_group, to_native(error)),
- exception=traceback.format_exc())
-
- def modify_policy_group(self):
- """
- Modify policy group.
- """
- policy_group_obj = netapp_utils.zapi.NaElement('qos-policy-group-modify')
- policy_group_obj.add_new_child('policy-group', self.parameters['name'])
- if self.parameters.get('max_throughput'):
- policy_group_obj.add_new_child('max-throughput', self.parameters['max_throughput'])
- if self.parameters.get('min_throughput'):
- policy_group_obj.add_new_child('min-throughput', self.parameters['min_throughput'])
- try:
- self.server.invoke_successfully(policy_group_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying qos policy group %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def rename_policy_group(self):
- """
- Rename policy group name.
- """
- rename_obj = netapp_utils.zapi.NaElement('qos-policy-group-rename')
- rename_obj.add_new_child('new-name', self.parameters['name'])
- rename_obj.add_new_child('policy-group-name', self.parameters['from_name'])
- try:
- self.server.invoke_successfully(rename_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error renaming qos policy group %s: %s' %
- (self.parameters['from_name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_helper(self, modify):
- """
- helper method to modify policy group.
- :param modify: modified attributes.
- """
- for attribute in modify.keys():
- if attribute in ['max_throughput', 'min_throughput']:
- self.modify_policy_group()
-
- def apply(self):
- """
- Run module based on playbook
- """
- self.asup_log_for_cserver("na_ontap_qos_policy_group")
- current = self.get_policy_group()
- rename, cd_action = None, None
- if self.parameters.get('from_name'):
- rename = self.na_helper.is_rename_action(self.get_policy_group(self.parameters['from_name']), current)
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_policy_group()
- if cd_action == 'create':
- self.create_policy_group()
- elif cd_action == 'delete':
- self.delete_policy_group()
- elif modify:
- self.modify_helper(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
-
-def main():
- '''Apply vserver operations from playbook'''
- qos_policy_group = NetAppOntapQosPolicyGroup()
- qos_policy_group.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_qtree.py b/lib/ansible/modules/storage/netapp/na_ontap_qtree.py
deleted file mode 100644
index 9dc1336b02..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_qtree.py
+++ /dev/null
@@ -1,303 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_qtree
-
-short_description: NetApp ONTAP manage qtrees
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create or destroy Qtrees.
-
-options:
-
- state:
- description:
- - Whether the specified qtree should exist or not.
- choices: ['present', 'absent']
- default: 'present'
-
- name:
- description:
- - The name of the qtree to manage.
- required: true
- type: str
-
- from_name:
- description:
- - Name of the qtree to be renamed.
- version_added: '2.7'
- type: str
-
- flexvol_name:
- description:
- - The name of the FlexVol the qtree should exist on. Required when C(state=present).
- required: true
- type: str
-
- vserver:
- description:
- - The name of the vserver to use.
- required: true
- type: str
-
- export_policy:
- description:
- - The name of the export policy to apply.
- version_added: '2.9'
- type: str
-
- security_style:
- description:
- - The security style for the qtree.
- choices: ['unix', 'ntfs', 'mixed']
- version_added: '2.9'
-
- oplocks:
- description:
- - Whether the oplocks should be enabled or not for the qtree.
- choices: ['enabled', 'disabled']
- version_added: '2.9'
-
- unix_permissions:
- description:
- - File permissions bits of the qtree.
- version_added: '2.9'
- type: str
-
-'''
-
-EXAMPLES = """
-- name: Create Qtrees
- na_ontap_qtree:
- state: present
- name: ansibleQTree
- flexvol_name: ansibleVolume
- export_policy: policyName
- security_style: mixed
- oplocks: disabled
- unix_permissions:
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-- name: Rename Qtrees
- na_ontap_qtree:
- state: present
- from_name: ansibleQTree_rename
- name: ansibleQTree
- flexvol_name: ansibleVolume
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-
-"""
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapQTree(object):
- '''Class with qtree operations'''
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False,
- choices=['present', 'absent'],
- default='present'),
- name=dict(required=True, type='str'),
- from_name=dict(required=False, type='str'),
- flexvol_name=dict(type='str'),
- vserver=dict(required=True, type='str'),
- export_policy=dict(required=False, type='str'),
- security_style=dict(required=False, choices=['unix', 'ntfs', 'mixed']),
- oplocks=dict(required=False, choices=['enabled', 'disabled']),
- unix_permissions=dict(required=False, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('state', 'present', ['flexvol_name'])
- ],
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=self.parameters['vserver'])
-
- def get_qtree(self, name=None):
- """
- Checks if the qtree exists.
- :param:
- name : qtree name
- :return:
- Details about the qtree
- False if qtree is not found
- :rtype: bool
- """
- if name is None:
- name = self.parameters['name']
-
- qtree_list_iter = netapp_utils.zapi.NaElement('qtree-list-iter')
- query_details = netapp_utils.zapi.NaElement.create_node_with_children(
- 'qtree-info', **{'vserver': self.parameters['vserver'],
- 'volume': self.parameters['flexvol_name'],
- 'qtree': name})
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- qtree_list_iter.add_child_elem(query)
- result = self.server.invoke_successfully(qtree_list_iter,
- enable_tunneling=True)
- return_q = None
- if (result.get_child_by_name('num-records') and
- int(result.get_child_content('num-records')) >= 1):
- return_q = {'export_policy': result['attributes-list']['qtree-info']['export-policy'],
- 'unix_permissions': result['attributes-list']['qtree-info']['mode'],
- 'oplocks': result['attributes-list']['qtree-info']['oplocks'],
- 'security_style': result['attributes-list']['qtree-info']['security-style']}
-
- return return_q
-
- def create_qtree(self):
- """
- Create a qtree
- """
- options = {'qtree': self.parameters['name'], 'volume': self.parameters['flexvol_name']}
- if self.parameters.get('export_policy'):
- options['export-policy'] = self.parameters['export_policy']
- if self.parameters.get('security_style'):
- options['security-style'] = self.parameters['security_style']
- if self.parameters.get('oplocks'):
- options['oplocks'] = self.parameters['oplocks']
- if self.parameters.get('unix_permissions'):
- options['mode'] = self.parameters['unix_permissions']
- qtree_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'qtree-create', **options)
- try:
- self.server.invoke_successfully(qtree_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error provisioning qtree %s: %s"
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_qtree(self):
- """
- Delete a qtree
- """
- path = '/vol/%s/%s' % (self.parameters['flexvol_name'], self.parameters['name'])
- qtree_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'qtree-delete', **{'qtree': path})
-
- try:
- self.server.invoke_successfully(qtree_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error deleting qtree %s: %s" % (path, to_native(error)),
- exception=traceback.format_exc())
-
- def rename_qtree(self):
- """
- Rename a qtree
- """
- path = '/vol/%s/%s' % (self.parameters['flexvol_name'], self.parameters['from_name'])
- new_path = '/vol/%s/%s' % (self.parameters['flexvol_name'], self.parameters['name'])
- qtree_rename = netapp_utils.zapi.NaElement.create_node_with_children(
- 'qtree-rename', **{'qtree': path,
- 'new-qtree-name': new_path})
-
- try:
- self.server.invoke_successfully(qtree_rename,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error renaming qtree %s: %s"
- % (self.parameters['from_name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_qtree(self):
- """
- Modify a qtree
- """
- options = {'qtree': self.parameters['name'], 'volume': self.parameters['flexvol_name']}
- if self.parameters.get('export_policy'):
- options['export-policy'] = self.parameters['export_policy']
- if self.parameters.get('security_style'):
- options['security-style'] = self.parameters['security_style']
- if self.parameters.get('oplocks'):
- options['oplocks'] = self.parameters['oplocks']
- if self.parameters.get('unix_permissions'):
- options['mode'] = self.parameters['unix_permissions']
- qtree_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'qtree-modify', **options)
- try:
- self.server.invoke_successfully(qtree_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying qtree %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- '''Call create/delete/modify/rename operations'''
- netapp_utils.ems_log_event("na_ontap_qtree", self.server)
- current = self.get_qtree()
- rename, cd_action, modify = None, None, None
- if self.parameters.get('from_name'):
- rename = self.na_helper.is_rename_action(self.get_qtree(self.parameters['from_name']), current)
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action is None and self.parameters['state'] == 'present':
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_qtree()
- if cd_action == 'create':
- self.create_qtree()
- elif cd_action == 'delete':
- self.delete_qtree()
- elif modify:
- self.modify_qtree()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- '''Apply qtree operations from playbook'''
- qtree_obj = NetAppOntapQTree()
- qtree_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_quotas.py b/lib/ansible/modules/storage/netapp/na_ontap_quotas.py
deleted file mode 100644
index 9a210b7246..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_quotas.py
+++ /dev/null
@@ -1,345 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-module: na_ontap_quotas
-short_description: NetApp ONTAP Quotas
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Set/Modify/Delete quota on ONTAP
-options:
- state:
- description:
- - Whether the specified quota should exist or not.
- choices: ['present', 'absent']
- default: present
- type: str
- vserver:
- required: true
- description:
- - Name of the vserver to use.
- type: str
- volume:
- description:
- - The name of the volume that the quota resides on.
- required: true
- type: str
- quota_target:
- description:
- - The quota target of the type specified.
- required: true
- type: str
- qtree:
- description:
- - Name of the qtree for the quota.
- - For user or group rules, it can be the qtree name or "" if no qtree.
- - For tree type rules, this field must be "".
- default: ""
- type: str
- type:
- description:
- - The type of quota rule
- choices: ['user', 'group', 'tree']
- required: true
- type: str
- policy:
- description:
- - Name of the quota policy from which the quota rule should be obtained.
- type: str
- set_quota_status:
- description:
- - Whether the specified volume should have quota status on or off.
- type: bool
- file_limit:
- description:
- - The number of files that the target can have.
- default: '-'
- type: str
- disk_limit:
- description:
- - The amount of disk space that is reserved for the target.
- default: '-'
- type: str
- threshold:
- description:
- - The amount of disk space the target would have to exceed before a message is logged.
- default: '-'
- type: str
-'''
-
-EXAMPLES = """
- - name: Add/Set quota
- na_ontap_quotas:
- state: present
- vserver: ansible
- volume: ansible
- quota_target: /vol/ansible
- type: user
- policy: ansible
- file_limit: 2
- disk_limit: 3
- set_quota_status: True
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: modify quota
- na_ontap_quotas:
- state: present
- vserver: ansible
- volume: ansible
- quota_target: /vol/ansible
- type: user
- policy: ansible
- file_limit: 2
- disk_limit: 3
- threshold: 3
- set_quota_status: False
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Delete quota
- na_ontap_quotas:
- state: absent
- vserver: ansible
- volume: ansible
- quota_target: /vol/ansible
- type: user
- policy: ansible
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-
-"""
-
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPQuotas(object):
- '''Class with quotas methods'''
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- volume=dict(required=True, type='str'),
- quota_target=dict(required=True, type='str'),
- qtree=dict(required=False, type='str', default=""),
- type=dict(required=True, type='str', choices=['user', 'group', 'tree']),
- policy=dict(required=False, type='str'),
- set_quota_status=dict(required=False, type='bool'),
- file_limit=dict(required=False, type='str', default='-'),
- disk_limit=dict(required=False, type='str', default='-'),
- threshold=dict(required=False, type='str', default='-')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_quota_status(self):
- """
- Return details about the quota status
- :param:
- name : volume name
- :return: status of the quota. None if not found.
- :rtype: dict
- """
- quota_status_get = netapp_utils.zapi.NaElement('quota-status')
- quota_status_get.translate_struct({
- 'volume': self.parameters['volume']
- })
- try:
- result = self.server.invoke_successfully(quota_status_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching quotas status info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result:
- return result['status']
- return None
-
- def get_quotas(self):
- """
- Get quota details
- :return: name of volume if quota exists, None otherwise
- """
- quota_get = netapp_utils.zapi.NaElement('quota-list-entries-iter')
- query = {
- 'query': {
- 'quota-entry': {
- 'volume': self.parameters['volume'],
- 'quota-target': self.parameters['quota_target'],
- 'quota-type': self.parameters['type'],
- 'vserver': self.parameters['vserver']
- }
- }
- }
- quota_get.translate_struct(query)
- if self.parameters.get('policy'):
- quota_get['query']['quota-entry'].add_new_child('policy', self.parameters['policy'])
- try:
- result = self.server.invoke_successfully(quota_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching quotas info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- return_values = {'volume': result['attributes-list']['quota-entry']['volume'],
- 'file_limit': result['attributes-list']['quota-entry']['file-limit'],
- 'disk_limit': result['attributes-list']['quota-entry']['disk-limit'],
- 'threshold': result['attributes-list']['quota-entry']['threshold']}
- return return_values
- return None
-
- def quota_entry_set(self):
- """
- Adds a quota entry
- """
- options = {'volume': self.parameters['volume'],
- 'quota-target': self.parameters['quota_target'],
- 'quota-type': self.parameters['type'],
- 'qtree': self.parameters['qtree'],
- 'file-limit': self.parameters['file_limit'],
- 'disk-limit': self.parameters['disk_limit'],
- 'threshold': self.parameters['threshold']}
- if self.parameters.get('policy'):
- options['policy'] = self.parameters['policy']
- set_entry = netapp_utils.zapi.NaElement.create_node_with_children(
- 'quota-set-entry', **options)
- try:
- self.server.invoke_successfully(set_entry, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error adding/modifying quota entry %s: %s'
- % (self.parameters['volume'], to_native(error)),
- exception=traceback.format_exc())
-
- def quota_entry_delete(self):
- """
- Deletes a quota entry
- """
- options = {'volume': self.parameters['volume'],
- 'quota-target': self.parameters['quota_target'],
- 'quota-type': self.parameters['type'],
- 'qtree': self.parameters['qtree']}
- set_entry = netapp_utils.zapi.NaElement.create_node_with_children(
- 'quota-delete-entry', **options)
- if self.parameters.get('policy'):
- set_entry.add_new_child('policy', self.parameters['policy'])
- try:
- self.server.invoke_successfully(set_entry, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting quota entry %s: %s'
- % (self.parameters['volume'], to_native(error)),
- exception=traceback.format_exc())
-
- def quota_entry_modify(self, modify_attrs):
- """
- Modifies a quota entry
- """
- options = {'volume': self.parameters['volume'],
- 'quota-target': self.parameters['quota_target'],
- 'quota-type': self.parameters['type'],
- 'qtree': self.parameters['qtree']}
- options.update(modify_attrs)
- if self.parameters.get('policy'):
- options['policy'] = str(self.parameters['policy'])
- modify_entry = netapp_utils.zapi.NaElement.create_node_with_children(
- 'quota-modify-entry', **options)
- try:
- self.server.invoke_successfully(modify_entry, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying quota entry %s: %s'
- % (self.parameters['volume'], to_native(error)),
- exception=traceback.format_exc())
-
- def on_or_off_quota(self, status):
- """
- on or off quota
- """
- quota = netapp_utils.zapi.NaElement.create_node_with_children(
- status, **{'volume': self.parameters['volume']})
- try:
- self.server.invoke_successfully(quota,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error setting %s for %s: %s'
- % (status, self.parameters['volume'], to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Apply action to quotas
- """
- netapp_utils.ems_log_event("na_ontap_quotas", self.server)
- modify_quota_status = None
- modify_quota = None
- current = self.get_quotas()
- if 'set_quota_status' in self.parameters:
- quota_status = self.get_quota_status()
- if quota_status is not None:
- quota_status_action = self.na_helper.get_modified_attributes(
- {'set_quota_status': True if quota_status == 'on' else False}, self.parameters)
- if quota_status_action:
- modify_quota_status = 'quota-on' if quota_status_action['set_quota_status'] else 'quota-off'
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action is None:
- modify_quota = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.quota_entry_set()
- elif cd_action == 'delete':
- self.quota_entry_delete()
- elif modify_quota is not None:
- for key in list(modify_quota):
- modify_quota[key.replace("_", "-")] = modify_quota.pop(key)
- self.quota_entry_modify(modify_quota)
- if modify_quota_status is not None:
- self.on_or_off_quota(modify_quota_status)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- '''Execute action'''
- quota_obj = NetAppONTAPQuotas()
- quota_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_security_key_manager.py b/lib/ansible/modules/storage/netapp/na_ontap_security_key_manager.py
deleted file mode 100644
index 598bacbd1c..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_security_key_manager.py
+++ /dev/null
@@ -1,229 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_security_key_manager
-
-short_description: NetApp ONTAP security key manager.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Add or delete or setup key management on NetApp ONTAP.
-
-options:
-
- state:
- description:
- - Whether the specified key manager should exist or not.
- choices: ['present', 'absent']
- default: 'present'
-
- ip_address:
- description:
- - The IP address of the key management server.
- required: true
-
- tcp_port:
- description:
- - The TCP port on which the key management server listens for incoming connections.
- default: 5696
-
- node:
- description:
- - The node which key management server runs on.
-
-'''
-
-EXAMPLES = """
-
- - name: Delete Key Manager
- tags:
- - delete
- na_ontap_security_key_manager:
- state: absent
- node: swenjun-vsim1
- hostname: "{{ hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- https: False
- ip_address: 0.0.0.0
-
- - name: Add Key Manager
- tags:
- - add
- na_ontap_security_key_manager:
- state: present
- node: swenjun-vsim1
- hostname: "{{ hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- https: False
- ip_address: 0.0.0.0
-
-"""
-
-RETURN = """
-"""
-
-import traceback
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapSecurityKeyManager(object):
- '''class with key manager operations'''
-
- def __init__(self):
- '''Initialize module parameters'''
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- ip_address=dict(required=True, type='str'),
- node=dict(required=False, type='str'),
- tcp_port=dict(required=False, type='int', default=5696)
- )
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required"
- )
- else:
- self.cluster = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def get_key_manager(self):
- """
- get key manager by ip address.
- :return: a dict of key manager
- """
- key_manager_info = netapp_utils.zapi.NaElement('security-key-manager-get-iter')
- query_details = netapp_utils.zapi.NaElement.create_node_with_children(
- 'key-manager-info', **{'key-manager-ip-address': self.parameters['ip_address']})
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- key_manager_info.add_child_elem(query)
-
- try:
- result = self.cluster.invoke_successfully(key_manager_info, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching key manager %s : %s'
- % (self.parameters['node'], to_native(error)),
- exception=traceback.format_exc())
-
- return_value = None
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) > 0:
- key_manager = result.get_child_by_name('attributes-list').get_child_by_name('key-manager-info')
- return_value = {}
- if key_manager.get_child_by_name('key-manager-ip-address'):
- return_value['ip_address'] = key_manager.get_child_content('key-manager-ip-address')
- if key_manager.get_child_by_name('key-manager-server-status'):
- return_value['server_status'] = key_manager.get_child_content('key-manager-server-status')
- if key_manager.get_child_by_name('key-manager-tcp-port'):
- return_value['tcp_port'] = key_manager.get_child_content('key-manager-tcp-port')
- if key_manager.get_child_by_name('node-name'):
- return_value['node'] = key_manager.get_child_content('node-name')
-
- return return_value
-
- def key_manager_setup(self):
- """
- set up external key manager.
- """
- key_manager_setup = netapp_utils.zapi.NaElement('security-key-manager-setup')
- # if specify on-boarding passphrase, it is on-boarding key management.
- # it not, then it's external key management.
- try:
- self.cluster.invoke_successfully(key_manager_setup, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error setting up key manager %s : %s'
- % (self.parameters['node'], to_native(error)),
- exception=traceback.format_exc())
-
- def create_key_manager(self):
- """
- add key manager.
- """
- key_manager_create = netapp_utils.zapi.NaElement('security-key-manager-add')
- key_manager_create.add_new_child('key-manager-ip-address', self.parameters['ip_address'])
- if self.parameters.get('tcp_port'):
- key_manager_create.add_new_child('key-manager-tcp-port', str(self.parameters['tcp_port']))
- try:
- self.cluster.invoke_successfully(key_manager_create, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating key manager %s : %s'
- % (self.parameters['node'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_key_manager(self):
- """
- delete key manager.
- """
- key_manager_delete = netapp_utils.zapi.NaElement('security-key-manager-delete')
- key_manager_delete.add_new_child('key-manager-ip-address', self.parameters['ip_address'])
- try:
- self.cluster.invoke_successfully(key_manager_delete, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting key manager %s : %s'
- % (self.parameters['node'], to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- self.asup_log_for_cserver("na_ontap_security_key_manager")
- self.key_manager_setup()
- current = self.get_key_manager()
- cd_action = None
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_key_manager()
- elif cd_action == 'delete':
- self.delete_key_manager()
- self.module.exit_json(changed=self.na_helper.changed)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.cluster)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
-
-def main():
- '''Apply volume operations from playbook'''
- obj = NetAppOntapSecurityKeyManager()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_service_processor_network.py b/lib/ansible/modules/storage/netapp/na_ontap_service_processor_network.py
deleted file mode 100644
index 14c974804b..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_service_processor_network.py
+++ /dev/null
@@ -1,284 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_service_processor_network
-short_description: NetApp ONTAP service processor network
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Modify a ONTAP service processor network
-options:
- state:
- description:
- - Whether the specified service processor network should exist or not.
- choices: ['present']
- default: present
- address_type:
- description:
- - Specify address class.
- required: true
- choices: ['ipv4', 'ipv6']
- is_enabled:
- description:
- - Specify whether to enable or disable the service processor network.
- required: true
- type: bool
- node:
- description:
- - The node where the service processor network should be enabled
- required: true
- dhcp:
- description:
- - Specify dhcp type.
- choices: ['v4', 'none']
- gateway_ip_address:
- description:
- - Specify the gateway ip.
- ip_address:
- description:
- - Specify the service processor ip address.
- netmask:
- description:
- - Specify the service processor netmask.
- prefix_length:
- description:
- - Specify the service processor prefix_length.
- wait_for_completion:
- description:
- - Set this parameter to 'true' for synchronous execution (wait until SP status is successfully updated)
- - Set this parameter to 'false' for asynchronous execution
- - For asynchronous, execution exits as soon as the request is sent, without checking SP status
- type: bool
- default: false
- version_added: '2.8'
-'''
-
-EXAMPLES = """
- - name: Modify Service Processor Network
- na_ontap_service_processor_network:
- state: present
- address_type: ipv4
- is_enabled: true
- dhcp: v4
- node: "{{ netapp_node }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
-"""
-
-RETURN = """
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-import time
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapServiceProcessorNetwork(object):
- """
- Modify a Service Processor Network
- """
-
- def __init__(self):
- """
- Initialize the NetAppOntapServiceProcessorNetwork class
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present'], default='present'),
- address_type=dict(required=True, choices=['ipv4', 'ipv6']),
- is_enabled=dict(required=True, type='bool'),
- node=dict(required=True, type='str'),
- dhcp=dict(required=False, choices=['v4', 'none']),
- gateway_ip_address=dict(required=False, type='str'),
- ip_address=dict(required=False, type='str'),
- netmask=dict(required=False, type='str'),
- prefix_length=dict(required=False, type='int'),
- wait_for_completion=dict(required=False, type='bool', default=False)
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- self.set_playbook_zapi_key_map()
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=None)
- return
-
- def set_playbook_zapi_key_map(self):
- self.na_helper.zapi_string_keys = {
- 'address_type': 'address-type',
- 'node': 'node',
- 'dhcp': 'dhcp',
- 'gateway_ip_address': 'gateway-ip-address',
- 'ip_address': 'ip-address',
- 'netmask': 'netmask'
- }
- self.na_helper.zapi_int_keys = {
- 'prefix_length': 'prefix-length'
- }
- self.na_helper.zapi_bool_keys = {
- 'is_enabled': 'is-enabled',
- }
- self.na_helper.zapi_required = {
- 'address_type': 'address-type',
- 'node': 'node',
- 'is_enabled': 'is-enabled'
- }
-
- def get_sp_network_status(self):
- """
- Return status of service processor network
- :param:
- name : name of the node
- :return: Status of the service processor network
- :rtype: dict
- """
- spn_get_iter = netapp_utils.zapi.NaElement('service-processor-network-get-iter')
- query_info = {
- 'query': {
- 'service-processor-network-info': {
- 'node': self.parameters['node'],
- 'address-type': self.parameters['address_type']
- }
- }
- }
- spn_get_iter.translate_struct(query_info)
- result = self.server.invoke_successfully(spn_get_iter, True)
- if int(result['num-records']) >= 1:
- sp_attr_info = result['attributes-list']['service-processor-network-info']
- return sp_attr_info.get_child_content('setup-status')
- return None
-
- def get_service_processor_network(self):
- """
- Return details about service processor network
- :param:
- name : name of the node
- :return: Details about service processor network. None if not found.
- :rtype: dict
- """
- spn_get_iter = netapp_utils.zapi.NaElement('service-processor-network-get-iter')
- query_info = {
- 'query': {
- 'service-processor-network-info': {
- 'node': self.parameters['node']
- }
- }
- }
- spn_get_iter.translate_struct(query_info)
- result = self.server.invoke_successfully(spn_get_iter, True)
- sp_details = None
- # check if job exists
- if int(result['num-records']) >= 1:
- sp_details = dict()
- sp_attr_info = result['attributes-list']['service-processor-network-info']
- for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
- sp_details[item_key] = sp_attr_info.get_child_content(zapi_key)
- for item_key, zapi_key in self.na_helper.zapi_bool_keys.items():
- sp_details[item_key] = self.na_helper.get_value_for_bool(from_zapi=True,
- value=sp_attr_info.get_child_content(zapi_key))
- for item_key, zapi_key in self.na_helper.zapi_int_keys.items():
- sp_details[item_key] = self.na_helper.get_value_for_int(from_zapi=True,
- value=sp_attr_info.get_child_content(zapi_key))
- return sp_details
-
- def modify_service_processor_network(self, params=None):
- """
- Modify a service processor network.
- :param params: A dict of modified options.
- When dhcp is not set to v4, ip_address, netmask, and gateway_ip_address must be specified even if remains the same.
- """
- if self.parameters['is_enabled'] is False:
- if params.get('is_enabled') and len(params) > 1:
- self.module.fail_json(msg='Error: Cannot modify any other parameter for a service processor network if option "is_enabled" is set to false.')
- elif params.get('is_enabled') is None and len(params) > 0:
- self.module.fail_json(msg='Error: Cannot modify a service processor network if it is disabled.')
-
- sp_modify = netapp_utils.zapi.NaElement('service-processor-network-modify')
- sp_modify.add_new_child("node", self.parameters['node'])
- sp_modify.add_new_child("address-type", self.parameters['address_type'])
- sp_attributes = dict()
- for item_key in self.parameters:
- if item_key in self.na_helper.zapi_string_keys:
- zapi_key = self.na_helper.zapi_string_keys.get(item_key)
- sp_attributes[zapi_key] = self.parameters[item_key]
- elif item_key in self.na_helper.zapi_bool_keys:
- zapi_key = self.na_helper.zapi_bool_keys.get(item_key)
- sp_attributes[zapi_key] = self.na_helper.get_value_for_bool(from_zapi=False, value=self.parameters[item_key])
- elif item_key in self.na_helper.zapi_int_keys:
- zapi_key = self.na_helper.zapi_int_keys.get(item_key)
- sp_attributes[zapi_key] = self.na_helper.get_value_for_int(from_zapi=False, value=self.parameters[item_key])
- sp_modify.translate_struct(sp_attributes)
- try:
- self.server.invoke_successfully(sp_modify, enable_tunneling=True)
- if self.parameters.get('wait_for_completion'):
- retries = 10
- while self.get_sp_network_status() == 'in_progress' and retries > 0:
- time.sleep(10)
- retries = retries - 1
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying service processor network: %s' % (to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_service_processor_network", cserver)
-
- def apply(self):
- """
- Run Module based on play book
- """
- self.autosupport_log()
- current = self.get_service_processor_network()
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if not current:
- self.module.fail_json(msg='Error No Service Processor for node: %s' % self.parameters['node'])
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- self.modify_service_processor_network(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Create the NetApp Ontap Service Processor Network Object and modify it
- """
-
- obj = NetAppOntapServiceProcessorNetwork()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_snapmirror.py b/lib/ansible/modules/storage/netapp/na_ontap_snapmirror.py
deleted file mode 100644
index aacfb32e81..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_snapmirror.py
+++ /dev/null
@@ -1,716 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Create/Delete/Initialize SnapMirror volume/vserver relationships for ONTAP/ONTAP
- - Create/Delete/Initialize SnapMirror volume relationship between ElementSW and ONTAP
- - Modify schedule for a SnapMirror relationship for ONTAP/ONTAP and ElementSW/ONTAP
- - Pre-requisite for ElementSW to ONTAP relationship or vice-versa is an established SnapMirror endpoint for ONTAP cluster with ElementSW UI
- - Pre-requisite for ElementSW to ONTAP relationship or vice-versa is to have SnapMirror enabled in the ElementSW volume
- - For creating a SnapMirror ElementSW/ONTAP relationship, an existing ONTAP/ElementSW relationship should be present
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_snapmirror
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified relationship should exist or not.
- default: present
- source_volume:
- description:
- - Specifies the name of the source volume for the SnapMirror.
- destination_volume:
- description:
- - Specifies the name of the destination volume for the SnapMirror.
- source_vserver:
- description:
- - Name of the source vserver for the SnapMirror.
- destination_vserver:
- description:
- - Name of the destination vserver for the SnapMirror.
- source_path:
- description:
- - Specifies the source endpoint of the SnapMirror relationship.
- - If the source is an ONTAP volume, format should be <[vserver:][volume]> or <[[cluster:]//vserver/]volume>
- - If the source is an ElementSW volume, format should be <[Element_SVIP]:/lun/[Element_VOLUME_ID]>
- - If the source is an ElementSW volume, the volume should have SnapMirror enabled.
- destination_path:
- description:
- - Specifies the destination endpoint of the SnapMirror relationship.
- relationship_type:
- choices: ['data_protection', 'load_sharing', 'vault', 'restore', 'transition_data_protection',
- 'extended_data_protection']
- description:
- - Specify the type of SnapMirror relationship.
- schedule:
- description:
- - Specify the name of the current schedule, which is used to update the SnapMirror relationship.
- - Optional for create, modifiable.
- policy:
- description:
- - Specify the name of the SnapMirror policy that applies to this relationship.
- version_added: "2.8"
- source_hostname:
- description:
- - Source hostname or management IP address for ONTAP or ElementSW cluster.
- - Required for SnapMirror delete
- source_username:
- description:
- - Source username for ONTAP or ElementSW cluster.
- - Optional if this is same as destination username.
- source_password:
- description:
- - Source password for ONTAP or ElementSW cluster.
- - Optional if this is same as destination password.
- connection_type:
- description:
- - Type of SnapMirror relationship.
- - Pre-requisite for either elementsw_ontap or ontap_elementsw the ElementSW volume should have enableSnapmirror option set to true.
- - For using ontap_elementsw, elementsw_ontap snapmirror relationship should exist.
- choices: ['ontap_ontap', 'elementsw_ontap', 'ontap_elementsw']
- default: ontap_ontap
- version_added: '2.9'
- max_transfer_rate:
- description:
- - Specifies the upper bound, in kilobytes per second, at which data is transferred.
- - Default is unlimited, it can be explicitly set to 0 as unlimited.
- type: int
- version_added: '2.9'
- identity_preserve:
- description:
- - Specifies whether or not the identity of the source Vserver is replicated to the destination Vserver.
- - If this parameter is set to true, the source Vserver's configuration will additionally be replicated to the destination.
- - If the parameter is set to false, then only the source Vserver's volumes and RBAC configuration are replicated to the destination.
- type: bool
- version_added: '2.9'
-short_description: "NetApp ONTAP or ElementSW Manage SnapMirror"
-version_added: "2.7"
-'''
-
-EXAMPLES = """
-
- # creates and initializes the snapmirror
- - name: Create ONTAP/ONTAP SnapMirror
- na_ontap_snapmirror:
- state: present
- source_volume: test_src
- destination_volume: test_dest
- source_vserver: ansible_src
- destination_vserver: ansible_dest
- schedule: hourly
- policy: MirrorAllSnapshots
- max_transfer_rate: 1000
- hostname: "{{ destination_cluster_hostname }}"
- username: "{{ destination_cluster_username }}"
- password: "{{ destination_cluster_password }}"
-
- # creates and initializes the snapmirror between vservers
- - name: Create ONTAP/ONTAP vserver SnapMirror
- na_ontap_snapmirror:
- state: present
- source_vserver: ansible_src
- destination_vserver: ansible_dest
- identity_preserve: true
- hostname: "{{ destination_cluster_hostname }}"
- username: "{{ destination_cluster_username }}"
- password: "{{ destination_cluster_password }}"
-
- # existing snapmirror relation with status 'snapmirrored' will be initialized
- - name: Initialize ONTAP/ONTAP SnapMirror
- na_ontap_snapmirror:
- state: present
- source_path: 'ansible:test'
- destination_path: 'ansible:dest'
- hostname: "{{ destination_cluster_hostname }}"
- username: "{{ destination_cluster_username }}"
- password: "{{ destination_cluster_password }}"
-
- - name: Delete SnapMirror
- na_ontap_snapmirror:
- state: absent
- destination_path: <path>
- source_hostname: "{{ source_hostname }}"
- hostname: "{{ destination_cluster_hostname }}"
- username: "{{ destination_cluster_username }}"
- password: "{{ destination_cluster_password }}"
-
- - name: Set schedule to NULL
- na_ontap_snapmirror:
- state: present
- destination_path: <path>
- schedule: ""
- hostname: "{{ destination_cluster_hostname }}"
- username: "{{ destination_cluster_username }}"
- password: "{{ destination_cluster_password }}"
-
- - name: Create SnapMirror from ElementSW to ONTAP
- na_ontap_snapmirror:
- state: present
- connection_type: elementsw_ontap
- source_path: '10.10.10.10:/lun/300'
- destination_path: 'ansible_test:ansible_dest_vol'
- schedule: hourly
- policy: MirrorLatest
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- source_hostname: " {{ Element_cluster_mvip }}"
- source_username: "{{ Element_cluster_username }}"
- source_password: "{{ Element_cluster_password }}"
-
- - name: Create SnapMirror from ONTAP to ElementSW
- na_ontap_snapmirror:
- state: present
- connection_type: ontap_elementsw
- destination_path: '10.10.10.10:/lun/300'
- source_path: 'ansible_test:ansible_dest_vol'
- policy: MirrorLatest
- hostname: "{{ Element_cluster_mvip }}"
- username: "{{ Element_cluster_username }}"
- password: "{{ Element_cluster_password }}"
- source_hostname: " {{ netapp_hostname }}"
- source_username: "{{ netapp_username }}"
- source_password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-import re
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_elementsw_module import NaElementSWModule
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-HAS_SF_SDK = netapp_utils.has_sf_sdk()
-try:
- import solidfire.common
-except ImportError:
- HAS_SF_SDK = False
-
-
-class NetAppONTAPSnapmirror(object):
- """
- Class with Snapmirror methods
- """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- source_vserver=dict(required=False, type='str'),
- destination_vserver=dict(required=False, type='str'),
- source_volume=dict(required=False, type='str'),
- destination_volume=dict(required=False, type='str'),
- source_path=dict(required=False, type='str'),
- destination_path=dict(required=False, type='str'),
- schedule=dict(required=False, type='str'),
- policy=dict(required=False, type='str'),
- relationship_type=dict(required=False, type='str',
- choices=['data_protection', 'load_sharing',
- 'vault', 'restore',
- 'transition_data_protection',
- 'extended_data_protection']
- ),
- source_hostname=dict(required=False, type='str'),
- connection_type=dict(required=False, type='str',
- choices=['ontap_ontap', 'elementsw_ontap', 'ontap_elementsw'],
- default='ontap_ontap'),
- source_username=dict(required=False, type='str'),
- source_password=dict(required=False, type='str', no_log=True),
- max_transfer_rate=dict(required=False, type='int'),
- identity_preserve=dict(required=False, type='bool')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_together=(['source_volume', 'destination_volume'],
- ['source_vserver', 'destination_vserver']),
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- # setup later if required
- self.source_server = None
- # only for ElementSW -> ONTAP snapmirroring, validate if ElementSW SDK is available
- if self.parameters.get('connection_type') in ['elementsw_ontap', 'ontap_elementsw']:
- if HAS_SF_SDK is False:
- self.module.fail_json(msg="Unable to import the SolidFire Python SDK")
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- if self.parameters.get('connection_type') != 'ontap_elementsw':
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- else:
- if self.parameters.get('source_username'):
- self.module.params['username'] = self.parameters['source_username']
- if self.parameters.get('source_password'):
- self.module.params['password'] = self.parameters['source_password']
- self.module.params['hostname'] = self.parameters['source_hostname']
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def set_element_connection(self, kind):
- if kind == 'source':
- self.module.params['hostname'] = self.parameters['source_hostname']
- self.module.params['username'] = self.parameters['source_username']
- self.module.params['password'] = self.parameters['source_password']
- elif kind == 'destination':
- self.module.params['hostname'] = self.parameters['hostname']
- self.module.params['username'] = self.parameters['username']
- self.module.params['password'] = self.parameters['password']
- elem = netapp_utils.create_sf_connection(module=self.module)
- elementsw_helper = NaElementSWModule(elem)
- return elementsw_helper, elem
-
- def snapmirror_get_iter(self, destination=None):
- """
- Compose NaElement object to query current SnapMirror relations using destination-path
- SnapMirror relation for a destination path is unique
- :return: NaElement object for SnapMirror-get-iter
- """
- snapmirror_get_iter = netapp_utils.zapi.NaElement('snapmirror-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- snapmirror_info = netapp_utils.zapi.NaElement('snapmirror-info')
- if destination is None:
- destination = self.parameters['destination_path']
- snapmirror_info.add_new_child('destination-location', destination)
- query.add_child_elem(snapmirror_info)
- snapmirror_get_iter.add_child_elem(query)
- return snapmirror_get_iter
-
- def snapmirror_get(self, destination=None):
- """
- Get current SnapMirror relations
- :return: Dictionary of current SnapMirror details if query successful, else None
- """
- snapmirror_get_iter = self.snapmirror_get_iter(destination)
- snap_info = dict()
- try:
- result = self.server.invoke_successfully(snapmirror_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching snapmirror info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) > 0:
- snapmirror_info = result.get_child_by_name('attributes-list').get_child_by_name(
- 'snapmirror-info')
- snap_info['mirror_state'] = snapmirror_info.get_child_content('mirror-state')
- snap_info['status'] = snapmirror_info.get_child_content('relationship-status')
- snap_info['schedule'] = snapmirror_info.get_child_content('schedule')
- snap_info['policy'] = snapmirror_info.get_child_content('policy')
- snap_info['relationship'] = snapmirror_info.get_child_content('relationship-type')
- if snapmirror_info.get_child_by_name('max-transfer-rate'):
- snap_info['max_transfer_rate'] = int(snapmirror_info.get_child_content('max-transfer-rate'))
- if snap_info['schedule'] is None:
- snap_info['schedule'] = ""
- return snap_info
- return None
-
- def check_if_remote_volume_exists(self):
- """
- Validate existence of source volume
- :return: True if volume exists, False otherwise
- """
- self.set_source_cluster_connection()
- # do a get volume to check if volume exists or not
- volume_info = netapp_utils.zapi.NaElement('volume-get-iter')
- volume_attributes = netapp_utils.zapi.NaElement('volume-attributes')
- volume_id_attributes = netapp_utils.zapi.NaElement('volume-id-attributes')
- volume_id_attributes.add_new_child('name', self.parameters['source_volume'])
- # if source_volume is present, then source_vserver is also guaranteed to be present
- volume_id_attributes.add_new_child('vserver-name', self.parameters['source_vserver'])
- volume_attributes.add_child_elem(volume_id_attributes)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(volume_attributes)
- volume_info.add_child_elem(query)
- try:
- result = self.source_server.invoke_successfully(volume_info, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching source volume details %s : %s'
- % (self.parameters['source_volume'], to_native(error)),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) > 0:
- return True
- return False
-
- def snapmirror_create(self):
- """
- Create a SnapMirror relationship
- """
- if self.parameters.get('source_hostname') and self.parameters.get('source_volume'):
- if not self.check_if_remote_volume_exists():
- self.module.fail_json(msg='Source volume does not exist. Please specify a volume that exists')
- options = {'source-location': self.parameters['source_path'],
- 'destination-location': self.parameters['destination_path']}
- snapmirror_create = netapp_utils.zapi.NaElement.create_node_with_children('snapmirror-create', **options)
- if self.parameters.get('relationship_type'):
- snapmirror_create.add_new_child('relationship-type', self.parameters['relationship_type'])
- if self.parameters.get('schedule'):
- snapmirror_create.add_new_child('schedule', self.parameters['schedule'])
- if self.parameters.get('policy'):
- snapmirror_create.add_new_child('policy', self.parameters['policy'])
- if self.parameters.get('max_transfer_rate'):
- snapmirror_create.add_new_child('max-transfer-rate', str(self.parameters['max_transfer_rate']))
- if self.parameters.get('identity_preserve'):
- snapmirror_create.add_new_child('identity-preserve', str(self.parameters['identity_preserve']))
- try:
- self.server.invoke_successfully(snapmirror_create, enable_tunneling=True)
- self.snapmirror_initialize()
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating SnapMirror %s' % to_native(error),
- exception=traceback.format_exc())
-
- def set_source_cluster_connection(self):
- """
- Setup ontap ZAPI server connection for source hostname
- :return: None
- """
- if self.parameters.get('source_username'):
- self.module.params['username'] = self.parameters['source_username']
- if self.parameters.get('source_password'):
- self.module.params['password'] = self.parameters['source_password']
- self.module.params['hostname'] = self.parameters['source_hostname']
- self.source_server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def delete_snapmirror(self, is_hci, relationship_type):
- """
- Delete a SnapMirror relationship
- #1. Quiesce the SnapMirror relationship at destination
- #2. Break the SnapMirror relationship at the destination
- #3. Release the SnapMirror at source
- #4. Delete SnapMirror at destination
- """
- if not is_hci:
- if not self.parameters.get('source_hostname'):
- self.module.fail_json(msg='Missing parameters for delete: Please specify the '
- 'source cluster hostname to release the SnapMirror relation')
- # Quiesce at destination
- self.snapmirror_quiesce()
- # Break at destination
- if relationship_type not in ['load_sharing', 'vault']:
- self.snapmirror_break()
- # if source is ONTAP, release the destination at source cluster
- if not is_hci:
- self.set_source_cluster_connection()
- if self.get_destination():
- # Release at source
- self.snapmirror_release()
- # Delete at destination
- self.snapmirror_delete()
-
- def snapmirror_quiesce(self):
- """
- Quiesce SnapMirror relationship - disable all future transfers to this destination
- """
- options = {'destination-location': self.parameters['destination_path']}
-
- snapmirror_quiesce = netapp_utils.zapi.NaElement.create_node_with_children(
- 'snapmirror-quiesce', **options)
- try:
- self.server.invoke_successfully(snapmirror_quiesce,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error Quiescing SnapMirror : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def snapmirror_delete(self):
- """
- Delete SnapMirror relationship at destination cluster
- """
- options = {'destination-location': self.parameters['destination_path']}
-
- snapmirror_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'snapmirror-destroy', **options)
- try:
- self.server.invoke_successfully(snapmirror_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting SnapMirror : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def snapmirror_break(self, destination=None):
- """
- Break SnapMirror relationship at destination cluster
- """
- if destination is None:
- destination = self.parameters['destination_path']
- options = {'destination-location': destination}
- snapmirror_break = netapp_utils.zapi.NaElement.create_node_with_children(
- 'snapmirror-break', **options)
- try:
- self.server.invoke_successfully(snapmirror_break,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error breaking SnapMirror relationship : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def snapmirror_release(self):
- """
- Release SnapMirror relationship from source cluster
- """
- options = {'destination-location': self.parameters['destination_path']}
- snapmirror_release = netapp_utils.zapi.NaElement.create_node_with_children(
- 'snapmirror-release', **options)
- try:
- self.source_server.invoke_successfully(snapmirror_release,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error releasing SnapMirror relationship : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def snapmirror_abort(self):
- """
- Abort a SnapMirror relationship in progress
- """
- options = {'destination-location': self.parameters['destination_path']}
- snapmirror_abort = netapp_utils.zapi.NaElement.create_node_with_children(
- 'snapmirror-abort', **options)
- try:
- self.server.invoke_successfully(snapmirror_abort,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error aborting SnapMirror relationship : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def snapmirror_initialize(self):
- """
- Initialize SnapMirror based on relationship type
- """
- current = self.snapmirror_get()
- if current['mirror_state'] != 'snapmirrored':
- initialize_zapi = 'snapmirror-initialize'
- if self.parameters.get('relationship_type') and self.parameters['relationship_type'] == 'load_sharing':
- initialize_zapi = 'snapmirror-initialize-ls-set'
- options = {'source-location': self.parameters['source_path']}
- else:
- options = {'destination-location': self.parameters['destination_path']}
- snapmirror_init = netapp_utils.zapi.NaElement.create_node_with_children(
- initialize_zapi, **options)
- try:
- self.server.invoke_successfully(snapmirror_init,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error initializing SnapMirror : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def snapmirror_modify(self, modify):
- """
- Modify SnapMirror schedule or policy
- """
- options = {'destination-location': self.parameters['destination_path']}
- snapmirror_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'snapmirror-modify', **options)
- if modify.get('schedule') is not None:
- snapmirror_modify.add_new_child('schedule', modify.get('schedule'))
- if modify.get('policy'):
- snapmirror_modify.add_new_child('policy', modify.get('policy'))
- if modify.get('max_transfer_rate'):
- snapmirror_modify.add_new_child('max-transfer-rate', str(modify.get('max_transfer_rate')))
- try:
- self.server.invoke_successfully(snapmirror_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying SnapMirror schedule or policy : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def snapmirror_update(self):
- """
- Update data in destination endpoint
- """
- options = {'destination-location': self.parameters['destination_path']}
- snapmirror_update = netapp_utils.zapi.NaElement.create_node_with_children(
- 'snapmirror-update', **options)
- try:
- result = self.server.invoke_successfully(snapmirror_update,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error updating SnapMirror : %s'
- % (to_native(error)),
- exception=traceback.format_exc())
-
- def check_parameters(self):
- """
- Validate parameters and fail if one or more required params are missing
- Update source and destination path from vserver and volume parameters
- """
- if self.parameters['state'] == 'present'\
- and (self.parameters.get('source_path') or self.parameters.get('destination_path')):
- if not self.parameters.get('destination_path') or not self.parameters.get('source_path'):
- self.module.fail_json(msg='Missing parameters: Source path or Destination path')
- elif self.parameters.get('source_volume'):
- if not self.parameters.get('source_vserver') or not self.parameters.get('destination_vserver'):
- self.module.fail_json(msg='Missing parameters: source vserver or destination vserver or both')
- self.parameters['source_path'] = self.parameters['source_vserver'] + ":" + self.parameters['source_volume']
- self.parameters['destination_path'] = self.parameters['destination_vserver'] + ":" +\
- self.parameters['destination_volume']
- elif self.parameters.get('source_vserver'):
- self.parameters['source_path'] = self.parameters['source_vserver'] + ":"
- self.parameters['destination_path'] = self.parameters['destination_vserver'] + ":"
-
- def get_destination(self):
- result = None
- release_get = netapp_utils.zapi.NaElement('snapmirror-get-destination-iter')
- query = netapp_utils.zapi.NaElement('query')
- snapmirror_dest_info = netapp_utils.zapi.NaElement('snapmirror-destination-info')
- snapmirror_dest_info.add_new_child('destination-location', self.parameters['destination_path'])
- query.add_child_elem(snapmirror_dest_info)
- release_get.add_child_elem(query)
- try:
- result = self.source_server.invoke_successfully(release_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching snapmirror destinations info: %s' % to_native(error),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) > 0:
- return True
- return None
-
- @staticmethod
- def element_source_path_format_matches(value):
- return re.match(pattern=r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\/lun\/[0-9]+",
- string=value)
-
- def check_elementsw_parameters(self, kind='source'):
- """
- Validate all ElementSW cluster parameters required for managing the SnapMirror relationship
- Validate if both source and destination paths are present
- Validate if source_path follows the required format
- Validate SVIP
- Validate if ElementSW volume exists
- :return: None
- """
- path = None
- if kind == 'destination':
- path = self.parameters.get('destination_path')
- elif kind == 'source':
- path = self.parameters.get('source_path')
- if path is None:
- self.module.fail_json(msg="Error: Missing required parameter %s_path for "
- "connection_type %s" % (kind, self.parameters['connection_type']))
- else:
- if NetAppONTAPSnapmirror.element_source_path_format_matches(path) is None:
- self.module.fail_json(msg="Error: invalid %s_path %s. "
- "If the path is a ElementSW cluster, the value should be of the format"
- " <Element_SVIP>:/lun/<Element_VOLUME_ID>" % (kind, path))
- # validate source_path
- elementsw_helper, elem = self.set_element_connection(kind)
- self.validate_elementsw_svip(path, elem)
- self.check_if_elementsw_volume_exists(path, elementsw_helper)
-
- def validate_elementsw_svip(self, path, elem):
- """
- Validate ElementSW cluster SVIP
- :return: None
- """
- result = None
- try:
- result = elem.get_cluster_info()
- except solidfire.common.ApiServerError as err:
- self.module.fail_json(msg="Error fetching SVIP", exception=to_native(err))
- if result and result.cluster_info.svip:
- cluster_svip = result.cluster_info.svip
- svip = path.split(':')[0] # split IP address from source_path
- if svip != cluster_svip:
- self.module.fail_json(msg="Error: Invalid SVIP")
-
- def check_if_elementsw_volume_exists(self, path, elementsw_helper):
- """
- Check if remote ElementSW volume exists
- :return: None
- """
- volume_id, vol_id = None, path.split('/')[-1]
- try:
- volume_id = elementsw_helper.volume_id_exists(int(vol_id))
- except solidfire.common.ApiServerError as err:
- self.module.fail_json(msg="Error fetching Volume details", exception=to_native(err))
-
- if volume_id is None:
- self.module.fail_json(msg="Error: Source volume does not exist in the ElementSW cluster")
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
- def apply(self):
- """
- Apply action to SnapMirror
- """
- self.asup_log_for_cserver("na_ontap_snapmirror")
- # source is ElementSW
- if self.parameters['state'] == 'present' and self.parameters.get('connection_type') == 'elementsw_ontap':
- self.check_elementsw_parameters()
- elif self.parameters.get('connection_type') == 'ontap_elementsw':
- self.check_elementsw_parameters('destination')
- else:
- self.check_parameters()
- if self.parameters['state'] == 'present' and self.parameters.get('connection_type') == 'ontap_elementsw':
- current_elementsw_ontap = self.snapmirror_get(self.parameters['source_path'])
- if current_elementsw_ontap is None:
- self.module.fail_json(msg='Error: creating an ONTAP to ElementSW snapmirror relationship requires an '
- 'established SnapMirror relation from ElementSW to ONTAP cluster')
- current = self.snapmirror_get()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- element_snapmirror = False
- if cd_action == 'create':
- self.snapmirror_create()
- elif cd_action == 'delete':
- if current['status'] == 'transferring':
- self.snapmirror_abort()
- else:
- if self.parameters.get('connection_type') == 'elementsw_ontap':
- element_snapmirror = True
- self.delete_snapmirror(element_snapmirror, current['relationship'])
- else:
- if modify:
- self.snapmirror_modify(modify)
- # check for initialize
- if current and current['mirror_state'] != 'snapmirrored':
- self.snapmirror_initialize()
- # set changed explicitly for initialize
- self.na_helper.changed = True
- # Update when create is called again, or modify is being called
- if self.parameters['state'] == 'present':
- self.snapmirror_update()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """Execute action"""
- community_obj = NetAppONTAPSnapmirror()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_snapshot.py b/lib/ansible/modules/storage/netapp/na_ontap_snapshot.py
deleted file mode 100644
index ba4b360074..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_snapshot.py
+++ /dev/null
@@ -1,326 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
-module: na_ontap_snapshot
-short_description: NetApp ONTAP manage Snapshots
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create/Modify/Delete ONTAP snapshots
-options:
- state:
- description:
- - If you want to create/modify a snapshot, or delete it.
- choices: ['present', 'absent']
- default: present
- snapshot:
- description:
- Name of the snapshot to be managed.
- The maximum string length is 256 characters.
- required: true
- from_name:
- description:
- - Name of the existing snapshot to be renamed to.
- version_added: '2.8'
- volume:
- description:
- - Name of the volume on which the snapshot is to be created.
- required: true
- async_bool:
- description:
- - If true, the snapshot is to be created asynchronously.
- type: bool
- comment:
- description:
- A human readable comment attached with the snapshot.
- The size of the comment can be at most 255 characters.
- snapmirror_label:
- description:
- A human readable SnapMirror Label attached with the snapshot.
- Size of the label can be at most 31 characters.
- ignore_owners:
- description:
- - if this field is true, snapshot will be deleted
- even if some other processes are accessing it.
- type: bool
- snapshot_instance_uuid:
- description:
- - The 128 bit unique snapshot identifier expressed in the form of UUID.
- vserver:
- description:
- - The Vserver name
- required: true
-'''
-EXAMPLES = """
- - name: create SnapShot
- tags:
- - create
- na_ontap_snapshot:
- state: present
- snapshot: "{{ snapshot name }}"
- volume: "{{ vol name }}"
- comment: "i am a comment"
- vserver: "{{ vserver name }}"
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
- hostname: "{{ netapp hostname }}"
- - name: delete SnapShot
- tags:
- - delete
- na_ontap_snapshot:
- state: absent
- snapshot: "{{ snapshot name }}"
- volume: "{{ vol name }}"
- vserver: "{{ vserver name }}"
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
- hostname: "{{ netapp hostname }}"
- - name: modify SnapShot
- tags:
- - modify
- na_ontap_snapshot:
- state: present
- snapshot: "{{ snapshot name }}"
- comment: "New comments are great"
- volume: "{{ vol name }}"
- vserver: "{{ vserver name }}"
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
- hostname: "{{ netapp hostname }}"
-"""
-
-RETURN = """
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapSnapshot(object):
- """
- Creates, modifies, and deletes a Snapshot
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- from_name=dict(required=False, type='str'),
- snapshot=dict(required=True, type="str"),
- volume=dict(required=True, type="str"),
- async_bool=dict(required=False, type="bool", default=False),
- comment=dict(required=False, type="str"),
- snapmirror_label=dict(required=False, type="str"),
- ignore_owners=dict(required=False, type="bool", default=False),
- snapshot_instance_uuid=dict(required=False, type="str"),
- vserver=dict(required=True, type="str"),
-
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=self.parameters['vserver'])
- return
-
- def get_snapshot(self, snapshot_name=None):
- """
- Checks to see if a snapshot exists or not
- :return: Return True if a snapshot exists, False if it doesn't
- """
- if snapshot_name is None:
- snapshot_name = self.parameters['snapshot']
- snapshot_obj = netapp_utils.zapi.NaElement("snapshot-get-iter")
- desired_attr = netapp_utils.zapi.NaElement("desired-attributes")
- snapshot_info = netapp_utils.zapi.NaElement('snapshot-info')
- comment = netapp_utils.zapi.NaElement('comment')
- snapmirror_label = netapp_utils.zapi.NaElement('snapmirror-label')
- # add more desired attributes that are allowed to be modified
- snapshot_info.add_child_elem(comment)
- snapshot_info.add_child_elem(snapmirror_label)
- desired_attr.add_child_elem(snapshot_info)
- snapshot_obj.add_child_elem(desired_attr)
- # compose query
- query = netapp_utils.zapi.NaElement("query")
- snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-info")
- snapshot_info_obj.add_new_child("name", snapshot_name)
- snapshot_info_obj.add_new_child("volume", self.parameters['volume'])
- snapshot_info_obj.add_new_child("vserver", self.parameters['vserver'])
- query.add_child_elem(snapshot_info_obj)
- snapshot_obj.add_child_elem(query)
- result = self.server.invoke_successfully(snapshot_obj, True)
- return_value = None
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
- attributes_list = result.get_child_by_name('attributes-list')
- snap_info = attributes_list.get_child_by_name('snapshot-info')
- return_value = {'comment': snap_info.get_child_content('comment')}
- if snap_info.get_child_by_name('snapmirror-label'):
- return_value['snapmirror_label'] = snap_info.get_child_content('snapmirror-label')
- else:
- return_value['snapmirror_label'] = None
- return return_value
-
- def create_snapshot(self):
- """
- Creates a new snapshot
- """
- snapshot_obj = netapp_utils.zapi.NaElement("snapshot-create")
-
- # set up required variables to create a snapshot
- snapshot_obj.add_new_child("snapshot", self.parameters['snapshot'])
- snapshot_obj.add_new_child("volume", self.parameters['volume'])
- # Set up optional variables to create a snapshot
- if self.parameters.get('async_bool'):
- snapshot_obj.add_new_child("async", str(self.parameters['async_bool']))
- if self.parameters.get('comment'):
- snapshot_obj.add_new_child("comment", self.parameters['comment'])
- if self.parameters.get('snapmirror_label'):
- snapshot_obj.add_new_child(
- "snapmirror-label", self.parameters['snapmirror_label'])
- try:
- self.server.invoke_successfully(snapshot_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating snapshot %s: %s' %
- (self.parameters['snapshot'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_snapshot(self):
- """
- Deletes an existing snapshot
- """
- snapshot_obj = netapp_utils.zapi.NaElement("snapshot-delete")
-
- # Set up required variables to delete a snapshot
- snapshot_obj.add_new_child("snapshot", self.parameters['snapshot'])
- snapshot_obj.add_new_child("volume", self.parameters['volume'])
- # set up optional variables to delete a snapshot
- if self.parameters.get('ignore_owners'):
- snapshot_obj.add_new_child("ignore-owners", str(self.parameters['ignore_owners']))
- if self.parameters.get('snapshot_instance_uuid'):
- snapshot_obj.add_new_child("snapshot-instance-uuid", self.parameters['snapshot_instance_uuid'])
- try:
- self.server.invoke_successfully(snapshot_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting snapshot %s: %s' %
- (self.parameters['snapshot'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_snapshot(self):
- """
- Modify an existing snapshot
- :return:
- """
- snapshot_obj = netapp_utils.zapi.NaElement("snapshot-modify-iter")
- # Create query object, this is the existing object
- query = netapp_utils.zapi.NaElement("query")
- snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-info")
- snapshot_info_obj.add_new_child("name", self.parameters['snapshot'])
- snapshot_info_obj.add_new_child("vserver", self.parameters['vserver'])
- query.add_child_elem(snapshot_info_obj)
- snapshot_obj.add_child_elem(query)
-
- # this is what we want to modify in the snapshot object
- attributes = netapp_utils.zapi.NaElement("attributes")
- snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-info")
- snapshot_info_obj.add_new_child("name", self.parameters['snapshot'])
- if self.parameters.get('comment'):
- snapshot_info_obj.add_new_child("comment", self.parameters['comment'])
- if self.parameters.get('snapmirror_label'):
- snapshot_info_obj.add_new_child("snapmirror-label", self.parameters['snapmirror_label'])
- attributes.add_child_elem(snapshot_info_obj)
- snapshot_obj.add_child_elem(attributes)
- try:
- self.server.invoke_successfully(snapshot_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying snapshot %s: %s' %
- (self.parameters['snapshot'], to_native(error)),
- exception=traceback.format_exc())
-
- def rename_snapshot(self):
- """
- Rename the snapshot
- """
- snapshot_obj = netapp_utils.zapi.NaElement("snapshot-rename")
-
- # set up required variables to rename a snapshot
- snapshot_obj.add_new_child("current-name", self.parameters['from_name'])
- snapshot_obj.add_new_child("new-name", self.parameters['snapshot'])
- snapshot_obj.add_new_child("volume", self.parameters['volume'])
- try:
- self.server.invoke_successfully(snapshot_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error renaming snapshot %s to %s: %s' %
- (self.parameters['from_name'], self.parameters['snapshot'], to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Check to see which play we should run
- """
- current = self.get_snapshot()
- netapp_utils.ems_log_event("na_ontap_snapshot", self.server)
- rename, cd_action = None, None
- modify = {}
- if self.parameters.get('from_name'):
- current_old_name = self.get_snapshot(self.parameters['from_name'])
- rename = self.na_helper.is_rename_action(current_old_name, current)
- modify = self.na_helper.get_modified_attributes(current_old_name, self.parameters)
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action is None:
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_snapshot()
- if cd_action == 'create':
- self.create_snapshot()
- elif cd_action == 'delete':
- self.delete_snapshot()
- elif modify:
- self.modify_snapshot()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Creates, modifies, and deletes a Snapshot
- """
- obj = NetAppOntapSnapshot()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_snapshot_policy.py b/lib/ansible/modules/storage/netapp/na_ontap_snapshot_policy.py
deleted file mode 100644
index 2e714f9f3d..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_snapshot_policy.py
+++ /dev/null
@@ -1,453 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
-module: na_ontap_snapshot_policy
-short_description: NetApp ONTAP manage Snapshot Policy
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create/Modify/Delete ONTAP snapshot policies
-options:
- state:
- description:
- - If you want to create, modify or delete a snapshot policy.
- choices: ['present', 'absent']
- default: present
- name:
- description:
- Name of the snapshot policy to be managed.
- The maximum string length is 256 characters.
- required: true
- enabled:
- description:
- - Status of the snapshot policy indicating whether the policy will be enabled or disabled.
- type: bool
- comment:
- description:
- A human readable comment attached with the snapshot.
- The size of the comment can be at most 255 characters.
- count:
- description:
- Retention count for the snapshots created by the schedule.
- type: list
- schedule:
- description:
- - Schedule to be added inside the policy.
- 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 = """
- - name: Create Snapshot policy
- na_ontap_snapshot_policy:
- state: present
- name: ansible2
- schedule: hourly
- count: 150
- enabled: True
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- 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: 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:
- state: absent
- name: ansible2
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- hostname: "{{ netapp_hostname }}"
- https: False
-"""
-
-RETURN = """
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapSnapshotPolicy(object):
- """
- Creates and deletes a Snapshot Policy
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- name=dict(required=True, type="str"),
- enabled=dict(required=False, type="bool"),
- # 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="list", elements="str"),
- snapmirror_label=dict(required=False, type="list", elements="str"),
- vserver=dict(required=False, type="str")
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('state', 'present', ['enabled', 'count', 'schedule']),
- ],
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- 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
-
- def get_snapshot_policy(self):
- """
- Checks to see if a snapshot policy exists or not
- :return: Return policy details if a snapshot policy exists, None if it doesn't
- """
- snapshot_obj = netapp_utils.zapi.NaElement("snapshot-policy-get-iter")
- # compose query
- query = netapp_utils.zapi.NaElement("query")
- snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-policy-info")
- 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)
- snapshot_obj.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(snapshot_obj, True)
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) == 1:
- 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:
- 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 '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']):
- self.module.fail_json(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")
-
- 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):
- """
- 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']),
- }
-
- 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
- positions = [str(i) for i in range(1, len(self.parameters['schedule']) + 1)]
- 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['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)
-
- # Set up optional variables to create a snapshot policy
- if self.parameters.get('comment'):
- snapshot_obj.add_new_child("comment", self.parameters['comment'])
- try:
- self.server.invoke_successfully(snapshot_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating snapshot policy %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_snapshot_policy(self):
- """
- Deletes an existing snapshot policy
- """
- snapshot_obj = netapp_utils.zapi.NaElement("snapshot-policy-delete")
-
- # Set up required variables to delete a snapshot policy
- snapshot_obj.add_new_child("policy", self.parameters['name'])
- try:
- self.server.invoke_successfully(snapshot_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting snapshot policy %s: %s' %
- (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
- def apply(self):
- """
- Check to see which play we should run
- """
- self.asup_log_for_cserver("na_ontap_snapshot_policy")
- current = self.get_snapshot_policy()
- modify = None
- 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.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_snapshot_policy()
- elif cd_action == 'delete':
- 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)
-
-
-def main():
- """
- Creates and deletes a Snapshot Policy
- """
- obj = NetAppOntapSnapshotPolicy()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_snmp.py b/lib/ansible/modules/storage/netapp/na_ontap_snmp.py
deleted file mode 100644
index caeadb9da3..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_snmp.py
+++ /dev/null
@@ -1,152 +0,0 @@
-#!/usr/bin/python
-"""
-create SNMP module to add/delete/modify SNMP user
-"""
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - "Create/Delete SNMP community"
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_snmp
-options:
- access_control:
- description:
- - "Access control for the community. The only supported value is 'ro' (read-only)"
- required: true
- community_name:
- description:
- - "The name of the SNMP community to manage."
- required: true
- state:
- choices: ['present', 'absent']
- description:
- - "Whether the specified SNMP community should exist or not."
- default: 'present'
-short_description: NetApp ONTAP SNMP community
-version_added: "2.6"
-'''
-
-EXAMPLES = """
- - name: Create SNMP community
- na_ontap_snmp:
- state: present
- community_name: communityName
- access_control: 'ro'
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- - name: Delete SNMP community
- na_ontap_snmp:
- state: absent
- community_name: communityName
- access_control: 'ro'
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPSnmp(object):
- '''Class with SNMP methods, doesn't support check mode'''
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- community_name=dict(required=True, type='str'),
- access_control=dict(required=True, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=False
- )
-
- parameters = self.module.params
- # set up state variables
- self.state = parameters['state']
- self.community_name = parameters['community_name']
- self.access_control = parameters['access_control']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def invoke_snmp_community(self, zapi):
- """
- Invoke zapi - add/delete take the same NaElement structure
- @return: SUCCESS / FAILURE with an error_message
- """
- snmp_community = netapp_utils.zapi.NaElement.create_node_with_children(
- zapi, **{'community': self.community_name,
- 'access-control': self.access_control})
- try:
- self.server.invoke_successfully(snmp_community, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError: # return False for duplicate entry
- return False
- return True
-
- def add_snmp_community(self):
- """
- Adds a SNMP community
- """
- return self.invoke_snmp_community('snmp-community-add')
-
- def delete_snmp_community(self):
- """
- Delete a SNMP community
- """
- return self.invoke_snmp_community('snmp-community-delete')
-
- def apply(self):
- """
- Apply action to SNMP community
- This module is not idempotent:
- Add doesn't fail the playbook if user is trying
- to add an already existing snmp community
- """
- changed = False
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_snmp", cserver)
- if self.state == 'present': # add
- if self.add_snmp_community():
- changed = True
- elif self.state == 'absent': # delete
- if self.delete_snmp_community():
- changed = True
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- '''Execute action'''
- community_obj = NetAppONTAPSnmp()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_software_update.py b/lib/ansible/modules/storage/netapp/na_ontap_software_update.py
deleted file mode 100644
index 7143827905..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_software_update.py
+++ /dev/null
@@ -1,301 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Update ONTAP software
- - Requires an https connection and is not supported over http
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_software_update
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified ONTAP package should update or not.
- default: present
- nodes:
- description:
- - List of nodes to be updated, the nodes have to be a part of a HA Pair.
- aliases:
- - node
- package_version:
- required: true
- description:
- - Specifies the package version to update software.
- package_url:
- required: true
- description:
- - Specifies the package URL to download the package.
- ignore_validation_warning:
- description:
- - Allows the update to continue if warnings are encountered during the validation phase.
- default: False
- type: bool
-short_description: NetApp ONTAP Update Software
-version_added: "2.7"
-'''
-
-EXAMPLES = """
-
- - name: ONTAP software update
- na_ontap_software_update:
- state: present
- nodes: vsim1
- package_url: "{{ url }}"
- package_version: "{{ version_name }}"
- ignore_validation_warning: True
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-import time
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPSoftwareUpdate(object):
- """
- Class with ONTAP software update methods
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- nodes=dict(required=False, type='list', aliases=["node"]),
- package_version=dict(required=True, type='str'),
- package_url=dict(required=True, type='str'),
- ignore_validation_warning=dict(required=False, type='bool', default=False)
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def cluster_image_get_iter(self):
- """
- Compose NaElement object to query current version
- :return: NaElement object for cluster-image-get-iter with query
- """
- cluster_image_get = netapp_utils.zapi.NaElement('cluster-image-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- cluster_image_info = netapp_utils.zapi.NaElement('cluster-image-info')
- query.add_child_elem(cluster_image_info)
- cluster_image_get.add_child_elem(query)
- return cluster_image_get
-
- def cluster_image_get(self):
- """
- Get current cluster image info
- :return: True if query successful, else return None
- """
- cluster_image_get_iter = self.cluster_image_get_iter()
- try:
- result = self.server.invoke_successfully(cluster_image_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching cluster image details: %s: %s'
- % (self.parameters['package_version'], to_native(error)),
- exception=traceback.format_exc())
- # return cluster image details
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) > 0:
- return True
- return None
-
- def cluster_image_get_for_node(self, node_name):
- """
- Get current cluster image info for given node
- """
- cluster_image_get = netapp_utils.zapi.NaElement('cluster-image-get')
- cluster_image_get.add_new_child('node-id', node_name)
- try:
- self.server.invoke_successfully(cluster_image_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching cluster image details for %s: %s'
- % (node_name, to_native(error)),
- exception=traceback.format_exc())
-
- def cluster_image_update_progress_get(self):
- """
- Get current cluster image update progress info
- :return: Dictionary of cluster image update progress if query successful, else return None
- """
- cluster_update_progress_get = netapp_utils.zapi.NaElement('cluster-image-update-progress-info')
- cluster_update_progress_info = dict()
- try:
- result = self.server.invoke_successfully(cluster_update_progress_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- # return empty dict on error to satisfy package delete upon image update
- if to_native(error.code) == 'Unexpected error' and self.parameters.get('https') is True:
- return cluster_update_progress_info
- else:
- self.module.fail_json(msg='Error fetching cluster image update progress details: %s'
- % (to_native(error)),
- exception=traceback.format_exc())
- # return cluster image update progress details
- if result.get_child_by_name('attributes').get_child_by_name('ndu-progress-info'):
- update_progress_info = result.get_child_by_name('attributes').get_child_by_name('ndu-progress-info')
- cluster_update_progress_info['overall_status'] = update_progress_info.get_child_content('overall-status')
- cluster_update_progress_info['completed_node_count'] = update_progress_info.\
- get_child_content('completed-node-count')
- return cluster_update_progress_info
-
- def cluster_image_update(self):
- """
- Update current cluster image
- """
- cluster_update_info = netapp_utils.zapi.NaElement('cluster-image-update')
- cluster_update_info.add_new_child('package-version', self.parameters['package_version'])
- cluster_update_info.add_new_child('ignore-validation-warning',
- str(self.parameters['ignore_validation_warning']))
- if self.parameters.get('nodes'):
- cluster_nodes = netapp_utils.zapi.NaElement('nodes')
- for node in self.parameters['nodes']:
- cluster_nodes.add_new_child('node-name', node)
- cluster_update_info.add_child_elem(cluster_nodes)
- try:
- self.server.invoke_successfully(cluster_update_info, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error updating cluster image for %s: %s'
- % (self.parameters['package_version'], to_native(error)),
- exception=traceback.format_exc())
-
- def cluster_image_package_download(self):
- """
- Get current cluster image package download
- :return: True if package already exists, else return False
- """
- cluster_image_package_download_info = netapp_utils.zapi.NaElement('cluster-image-package-download')
- cluster_image_package_download_info.add_new_child('package-url', self.parameters['package_url'])
- try:
- self.server.invoke_successfully(cluster_image_package_download_info, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- # Error 18408 denotes Package image with the same name already exists
- if to_native(error.code) == "18408":
- return True
- else:
- self.module.fail_json(msg='Error downloading cluster image package for %s: %s'
- % (self.parameters['package_url'], to_native(error)),
- exception=traceback.format_exc())
- return False
-
- def cluster_image_package_delete(self):
- """
- Delete current cluster image package
- """
- cluster_image_package_delete_info = netapp_utils.zapi.NaElement('cluster-image-package-delete')
- cluster_image_package_delete_info.add_new_child('package-version', self.parameters['package_version'])
- try:
- self.server.invoke_successfully(cluster_image_package_delete_info, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting cluster image package for %s: %s'
- % (self.parameters['package_version'], to_native(error)),
- exception=traceback.format_exc())
-
- def cluster_image_package_download_progress(self):
- """
- Get current cluster image package download progress
- :return: Dictionary of cluster image download progress if query successful, else return None
- """
- cluster_image_package_download_progress_info = netapp_utils.zapi.\
- NaElement('cluster-image-get-download-progress')
- try:
- result = self.server.invoke_successfully(
- cluster_image_package_download_progress_info, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching cluster image package download progress for %s: %s'
- % (self.parameters['package_url'], to_native(error)),
- exception=traceback.format_exc())
- # return cluster image download progress details
- cluster_download_progress_info = dict()
- if result.get_child_by_name('progress-status'):
- cluster_download_progress_info['progress_status'] = result.get_child_content('progress-status')
- cluster_download_progress_info['progress_details'] = result.get_child_content('progress-details')
- cluster_download_progress_info['failure_reason'] = result.get_child_content('failure-reason')
- return cluster_download_progress_info
- return None
-
- def autosupport_log(self):
- """
- Autosupport log for software_update
- :return:
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_software_update", cserver)
-
- def apply(self):
- """
- Apply action to update ONTAP software
- """
- if self.parameters.get('https') is not True:
- self.module.fail_json(msg='https parameter must be True')
- changed = False
- self.autosupport_log()
- current = self.cluster_image_get()
- if self.parameters.get('nodes'):
- for node in self.parameters['nodes']:
- self.cluster_image_get_for_node(node)
- if self.parameters.get('state') == 'present' and current:
- package_exists = self.cluster_image_package_download()
- if package_exists is False:
- cluster_download_progress = self.cluster_image_package_download_progress()
- while cluster_download_progress.get('progress_status') == 'async_pkg_get_phase_running':
- time.sleep(5)
- cluster_download_progress = self.cluster_image_package_download_progress()
- if cluster_download_progress.get('progress_status') == 'async_pkg_get_phase_complete':
- self.cluster_image_update()
- changed = True
- else:
- self.module.fail_json(msg='Error downloading package: %s'
- % (cluster_download_progress['failure_reason']))
- else:
- self.cluster_image_update()
- changed = True
- # delete package once update is completed
- cluster_update_progress = self.cluster_image_update_progress_get()
- while not cluster_update_progress or cluster_update_progress.get('overall_status') == 'in_progress':
- time.sleep(25)
- cluster_update_progress = self.cluster_image_update_progress_get()
- if cluster_update_progress.get('overall_status') == 'completed':
- self.cluster_image_package_delete()
- self.module.exit_json(changed=changed)
-
-
-def main():
- """Execute action"""
- community_obj = NetAppONTAPSoftwareUpdate()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_svm.py b/lib/ansible/modules/storage/netapp/na_ontap_svm.py
deleted file mode 100644
index 75418c709e..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_svm.py
+++ /dev/null
@@ -1,444 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_svm
-
-short_description: NetApp ONTAP SVM
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create, modify or delete SVM on NetApp ONTAP
-
-options:
-
- state:
- description:
- - Whether the specified SVM should exist or not.
- choices: ['present', 'absent']
- default: 'present'
-
- name:
- description:
- - The name of the SVM to manage.
- required: true
-
- from_name:
- description:
- - Name of the SVM to be renamed
- version_added: '2.7'
-
- root_volume:
- description:
- - Root volume of the SVM.
- - Cannot be modified after creation.
-
- root_volume_aggregate:
- description:
- - The aggregate on which the root volume will be created.
- - Cannot be modified after creation.
-
- root_volume_security_style:
- description:
- - Security Style of the root volume.
- - When specified as part of the vserver-create,
- this field represents the security style for the Vserver root volume.
- - When specified as part of vserver-get-iter call,
- this will return the list of matching Vservers.
- - The 'unified' security style, which applies only to Infinite Volumes,
- cannot be applied to a Vserver's root volume.
- - Cannot be modified after creation.
- choices: ['unix', 'ntfs', 'mixed', 'unified']
-
- allowed_protocols:
- description:
- - Allowed Protocols.
- - When specified as part of a vserver-create,
- this field represent the list of protocols allowed on the Vserver.
- - When part of vserver-get-iter call,
- this will return the list of Vservers
- which have any of the protocols specified
- as part of the allowed-protocols.
- - When part of vserver-modify,
- this field should include the existing list
- along with new protocol list to be added to prevent data disruptions.
- - Possible values
- - nfs NFS protocol,
- - cifs CIFS protocol,
- - fcp FCP protocol,
- - iscsi iSCSI protocol,
- - ndmp NDMP protocol,
- - http HTTP protocol,
- - nvme NVMe protocol
-
- aggr_list:
- description:
- - List of aggregates assigned for volume operations.
- - These aggregates could be shared for use with other Vservers.
- - When specified as part of a vserver-create,
- this field represents the list of aggregates
- that are assigned to the Vserver for volume operations.
- - When part of vserver-get-iter call,
- this will return the list of Vservers
- which have any of the aggregates specified as part of the aggr list.
-
- ipspace:
- description:
- - IPSpace name
- - Cannot be modified after creation.
- version_added: '2.7'
-
-
- snapshot_policy:
- description:
- - Default snapshot policy setting for all volumes of the Vserver.
- This policy will be assigned to all volumes created in this
- Vserver unless the volume create request explicitly provides a
- snapshot policy or volume is modified later with a specific
- snapshot policy. A volume-level snapshot policy always overrides
- the default Vserver-wide snapshot policy.
- version_added: '2.7'
-
- language:
- description:
- - Language to use for the SVM
- - Default to C.UTF-8
- - Possible values Language
- - c POSIX
- - ar Arabic
- - cs Czech
- - da Danish
- - de German
- - en English
- - en_us English (US)
- - es Spanish
- - fi Finnish
- - fr French
- - he Hebrew
- - hr Croatian
- - hu Hungarian
- - it Italian
- - ja Japanese euc-j
- - ja_v1 Japanese euc-j
- - ja_jp.pck Japanese PCK (sjis)
- - ja_jp.932 Japanese cp932
- - ja_jp.pck_v2 Japanese PCK (sjis)
- - ko Korean
- - no Norwegian
- - nl Dutch
- - pl Polish
- - pt Portuguese
- - ro Romanian
- - ru Russian
- - sk Slovak
- - sl Slovenian
- - sv Swedish
- - tr Turkish
- - zh Simplified Chinese
- - zh.gbk Simplified Chinese (GBK)
- - zh_tw Traditional Chinese euc-tw
- - zh_tw.big5 Traditional Chinese Big 5
- version_added: '2.7'
-
- subtype:
- description:
- - The subtype for vserver to be created.
- - Cannot be modified after creation.
- choices: ['default', 'dp_destination', 'sync_source', 'sync_destination']
- version_added: '2.7'
-
- comment:
- description:
- - When specified as part of a vserver-create, this field represents the comment associated with the Vserver.
- - When part of vserver-get-iter call, this will return the list of matching Vservers.
- version_added: '2.8'
-'''
-
-EXAMPLES = """
-
- - name: Create SVM
- na_ontap_svm:
- state: present
- name: ansibleVServer
- root_volume: vol1
- root_volume_aggregate: aggr1
- root_volume_security_style: mixed
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-"""
-
-RETURN = """
-"""
-import traceback
-
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapSVM(object):
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- from_name=dict(required=False, type='str'),
- root_volume=dict(type='str'),
- root_volume_aggregate=dict(type='str'),
- root_volume_security_style=dict(type='str', choices=['unix',
- 'ntfs',
- 'mixed',
- 'unified'
- ]),
- allowed_protocols=dict(type='list'),
- aggr_list=dict(type='list'),
- ipspace=dict(type='str', required=False),
- snapshot_policy=dict(type='str', required=False),
- language=dict(type='str', required=False),
- subtype=dict(choices=['default', 'dp_destination', 'sync_source', 'sync_destination']),
- comment=dict(type="str", required=False)
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def get_vserver(self, vserver_name=None):
- """
- Checks if vserver exists.
-
- :return:
- vserver object if vserver found
- None if vserver is not found
- :rtype: object/None
- """
- if vserver_name is None:
- vserver_name = self.parameters['name']
-
- vserver_info = netapp_utils.zapi.NaElement('vserver-get-iter')
- query_details = netapp_utils.zapi.NaElement.create_node_with_children(
- 'vserver-info', **{'vserver-name': vserver_name})
-
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- vserver_info.add_child_elem(query)
-
- result = self.server.invoke_successfully(vserver_info,
- enable_tunneling=False)
- vserver_details = None
- if (result.get_child_by_name('num-records') and
- int(result.get_child_content('num-records')) >= 1):
- attributes_list = result.get_child_by_name('attributes-list')
- vserver_info = attributes_list.get_child_by_name('vserver-info')
- aggr_list = list()
- ''' vserver aggr-list can be empty by default'''
- get_list = vserver_info.get_child_by_name('aggr-list')
- if get_list is not None:
- aggregates = get_list.get_children()
- for aggr in aggregates:
- aggr_list.append(aggr.get_content())
-
- protocols = list()
- '''allowed-protocols is not empty for data SVM, but is for node SVM'''
- allowed_protocols = vserver_info.get_child_by_name('allowed-protocols')
- if allowed_protocols is not None:
- get_protocols = allowed_protocols.get_children()
- for protocol in get_protocols:
- protocols.append(protocol.get_content())
- vserver_details = {'name': vserver_info.get_child_content('vserver-name'),
- 'root_volume': vserver_info.get_child_content('root-volume'),
- 'root_volume_aggregate': vserver_info.get_child_content('root-volume-aggregate'),
- 'root_volume_security_style': vserver_info.get_child_content('root-volume-security-style'),
- 'subtype': vserver_info.get_child_content('vserver-subtype'),
- 'aggr_list': aggr_list,
- 'language': vserver_info.get_child_content('language'),
- 'snapshot_policy': vserver_info.get_child_content('snapshot-policy'),
- 'allowed_protocols': protocols,
- 'ipspace': vserver_info.get_child_content('ipspace'),
- 'comment': vserver_info.get_child_content('comment')}
- return vserver_details
-
- def create_vserver(self):
- options = {'vserver-name': self.parameters['name']}
- self.add_parameter_to_dict(options, 'root_volume', 'root-volume')
- self.add_parameter_to_dict(options, 'root_volume_aggregate', 'root-volume-aggregate')
- self.add_parameter_to_dict(options, 'root_volume_security_style', 'root-volume-security-style')
- self.add_parameter_to_dict(options, 'language', 'language')
- self.add_parameter_to_dict(options, 'ipspace', 'ipspace')
- self.add_parameter_to_dict(options, 'snapshot_policy', 'snapshot-policy')
- self.add_parameter_to_dict(options, 'subtype', 'vserver-subtype')
- self.add_parameter_to_dict(options, 'comment', 'comment')
- vserver_create = netapp_utils.zapi.NaElement.create_node_with_children('vserver-create', **options)
- try:
- self.server.invoke_successfully(vserver_create,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error provisioning SVM %s: %s'
- % (self.parameters['name'], to_native(e)),
- exception=traceback.format_exc())
- # add allowed-protocols, aggr-list after creation,
- # since vserver-create doesn't allow these attributes during creation
- options = dict()
- for key in ('allowed_protocols', 'aggr_list'):
- if self.parameters.get(key):
- options[key] = self.parameters[key]
- if options:
- self.modify_vserver(options)
-
- def delete_vserver(self):
- vserver_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'vserver-destroy', **{'vserver-name': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(vserver_delete,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error deleting SVM %s: %s'
- % (self.parameters['name'], to_native(e)),
- exception=traceback.format_exc())
-
- def rename_vserver(self):
- vserver_rename = netapp_utils.zapi.NaElement.create_node_with_children(
- 'vserver-rename', **{'vserver-name': self.parameters['from_name'],
- 'new-name': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(vserver_rename,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error renaming SVM %s: %s'
- % (self.parameters['from_name'], to_native(e)),
- exception=traceback.format_exc())
-
- def modify_vserver(self, modify):
- '''
- Modify vserver.
- :param modify: list of modify attributes
- '''
- vserver_modify = netapp_utils.zapi.NaElement('vserver-modify')
- vserver_modify.add_new_child('vserver-name', self.parameters['name'])
- for attribute in modify:
- if attribute == 'language':
- vserver_modify.add_new_child('language', self.parameters['language'])
- if attribute == 'snapshot_policy':
- vserver_modify.add_new_child('snapshot_policy', self.parameters['snapshot_policy'])
- if attribute == 'comment':
- vserver_modify.add_new_child('comment', self.parameters['comment'])
- if attribute == 'allowed_protocols':
- allowed_protocols = netapp_utils.zapi.NaElement('allowed-protocols')
- for protocol in self.parameters['allowed_protocols']:
- allowed_protocols.add_new_child('protocol', protocol)
- vserver_modify.add_child_elem(allowed_protocols)
- if attribute == 'aggr_list':
- aggregates = netapp_utils.zapi.NaElement('aggr-list')
- for aggr in self.parameters['aggr_list']:
- aggregates.add_new_child('aggr-name', aggr)
- vserver_modify.add_child_elem(aggregates)
- try:
- self.server.invoke_successfully(vserver_modify,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error modifying SVM %s: %s'
- % (self.parameters['name'], to_native(e)),
- exception=traceback.format_exc())
-
- def add_parameter_to_dict(self, adict, name, key=None, tostr=False):
- '''
- add defined parameter (not None) to adict using key.
- :param adict: a dictionary.
- :param name: name in self.parameters.
- :param key: key in adict.
- :param tostr: boolean.
- '''
- if key is None:
- key = name
- if self.parameters.get(name) is not None:
- if tostr:
- adict[key] = str(self.parameters.get(name))
- else:
- adict[key] = self.parameters.get(name)
-
- def apply(self):
- '''Call create/modify/delete operations.'''
- self.asup_log_for_cserver("na_ontap_svm")
- current = self.get_vserver()
- cd_action, rename = None, None
- if self.parameters.get('from_name'):
- rename = self.na_helper.is_rename_action(self.get_vserver(self.parameters['from_name']), current)
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- for attribute in modify:
- if attribute in ['root_volume', 'root_volume_aggregate', 'root_volume_security_style', 'subtype', 'ipspace']:
- self.module.fail_json(msg='Error modifying SVM %s: can not modify %s.' % (self.parameters['name'], attribute))
- if attribute == 'language':
- # Ontap documentation uses C.UTF-8, but actually stores as c.utf_8.
- if self.parameters['language'].lower() == 'c.utf-8':
- self.parameters['language'] = 'c.utf_8'
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_vserver()
- # If rename is True, cd_action is None, but modify could be true or false.
- if cd_action == 'create':
- self.create_vserver()
- elif cd_action == 'delete':
- self.delete_vserver()
- elif modify:
- self.modify_vserver(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
-
-def main():
- '''Apply vserver operations from playbook'''
- v = NetAppOntapSVM()
- v.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_svm_options.py b/lib/ansible/modules/storage/netapp/na_ontap_svm_options.py
deleted file mode 100644
index b67453a848..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_svm_options.py
+++ /dev/null
@@ -1,156 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
-short_description: NetApp ONTAP Modify SVM Options
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Modify ONTAP SVM Options
- - Only Options that appear on "vserver options show" can be set
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_svm_options
-version_added: "2.7"
-options:
- name:
- description:
- - Name of the option.
- value:
- description:
- - Value of the option.
- - Value must be in quote
- vserver:
- description:
- - The name of the vserver to which this option belongs to.
- required: True
-'''
-
-EXAMPLES = """
- - name: Set SVM Options
- na_ontap_svm_options:
- vserver: "{{ netapp_vserver_name }}"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- name: snmp.enable
- value: 'on'
-"""
-
-RETURN = """
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPSvnOptions(object):
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- name=dict(required=False, type="str", default=None),
- value=dict(required=False, type='str', default=None),
- vserver=dict(required=True, type='str')
-
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
- return
-
- def set_options(self):
- """
- Set a specific option
- :return: None
- """
- option_obj = netapp_utils.zapi.NaElement("options-set")
- option_obj.add_new_child('name', self.parameters['name'])
- option_obj.add_new_child('value', self.parameters['value'])
- try:
- result = self.server.invoke_successfully(option_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error setting options: %s" % to_native(error), exception=traceback.format_exc())
-
- def list_options(self):
- """
- List all Options on the Vserver
- :return: None
- """
- option_obj = netapp_utils.zapi.NaElement("options-list-info")
- try:
- result = self.server.invoke_successfully(option_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error getting options: %s" % to_native(error), exception=traceback.format_exc())
-
- def is_option_set(self):
- """
- Checks to see if an option is set or not
- :return: If option is set return True, else return False
- """
- option_obj = netapp_utils.zapi.NaElement("options-get-iter")
- options_info = netapp_utils.zapi.NaElement("option-info")
- if self.parameters.get('name') is not None:
- options_info.add_new_child("name", self.parameters['name'])
- if self.parameters.get('value') is not None:
- options_info.add_new_child("value", self.parameters['value'])
- if "vserver" in self.parameters.keys():
- if self.parameters['vserver'] is not None:
- options_info.add_new_child("vserver", self.parameters['vserver'])
- query = netapp_utils.zapi.NaElement("query")
- query.add_child_elem(options_info)
- option_obj.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(option_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error finding option: %s" % to_native(error), exception=traceback.format_exc())
-
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- return True
- return False
-
- def apply(self):
- changed = False
- netapp_utils.ems_log_event("na_ontap_svm_options", self.server)
- is_set = self.is_option_set()
- if not is_set:
- self.set_options()
- changed = True
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Execute action from playbook
- :return: none
- """
- cg_obj = NetAppONTAPSvnOptions()
- cg_obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_ucadapter.py b/lib/ansible/modules/storage/netapp/na_ontap_ucadapter.py
deleted file mode 100644
index 75956c1676..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_ucadapter.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'
-}
-
-DOCUMENTATION = '''
----
-
-module: na_ontap_ucadapter
-short_description: NetApp ONTAP UC adapter configuration
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - modify the UC adapter mode and type taking pending type and mode into account.
-
-options:
- state:
- description:
- - Whether the specified adapter should exist.
- required: false
- choices: ['present']
- default: 'present'
-
- adapter_name:
- description:
- - Specifies the adapter name.
- required: true
-
- node_name:
- description:
- - Specifies the adapter home node.
- required: true
-
- mode:
- description:
- - Specifies the mode of the adapter.
-
- type:
- description:
- - Specifies the fc4 type of the adapter.
-
-'''
-
-EXAMPLES = '''
- - name: Modify adapter
- na_ontap_adapter:
- state: present
- adapter_name: data2
- node_name: laurentn-vsim1
- mode: fc
- type: target
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-'''
-
-RETURN = '''
-'''
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapadapter(object):
- ''' object to describe adapter info '''
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present'], default='present'),
- adapter_name=dict(required=True, type='str'),
- node_name=dict(required=True, type='str'),
- mode=dict(required=False, type='str'),
- type=dict(required=False, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def get_adapter(self):
- """
- Return details about the adapter
- :param:
- name : Name of the name of the adapter
-
- :return: Details about the adapter. None if not found.
- :rtype: dict
- """
- adapter_info = netapp_utils.zapi.NaElement('ucm-adapter-get')
- adapter_info.add_new_child('adapter-name', self.parameters['adapter_name'])
- adapter_info.add_new_child('node-name', self.parameters['node_name'])
- try:
- result = self.server.invoke_successfully(adapter_info, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching ucadapter details: %s: %s'
- % (self.parameters['node_name'], to_native(error)),
- exception=traceback.format_exc())
- if result.get_child_by_name('attributes'):
- adapter_attributes = result.get_child_by_name('attributes').\
- get_child_by_name('uc-adapter-info')
- return_value = {
- 'mode': adapter_attributes.get_child_content('mode'),
- 'pending-mode': adapter_attributes.get_child_content('pending-mode'),
- 'type': adapter_attributes.get_child_content('fc4-type'),
- 'pending-type': adapter_attributes.get_child_content('pending-fc4-type'),
- 'status': adapter_attributes.get_child_content('status'),
- }
- return return_value
- return None
-
- def modify_adapter(self):
- """
- Modify the adapter.
- """
- params = {'adapter-name': self.parameters['adapter_name'],
- 'node-name': self.parameters['node_name']}
- if self.parameters['type'] is not None:
- params['fc4-type'] = self.parameters['type']
- if self.parameters['mode'] is not None:
- params['mode'] = self.parameters['mode']
- adapter_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'ucm-adapter-modify', ** params)
- try:
- self.server.invoke_successfully(adapter_modify,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error modifying adapter %s: %s' % (self.parameters['adapter_name'], to_native(e)),
- exception=traceback.format_exc())
-
- def online_or_offline_adapter(self, status):
- """
- Bring a Fibre Channel target adapter offline/online.
- """
- if status == 'down':
- adapter = netapp_utils.zapi.NaElement('fcp-adapter-config-down')
- elif status == 'up':
- adapter = netapp_utils.zapi.NaElement('fcp-adapter-config-up')
- adapter.add_new_child('fcp-adapter', self.parameters['adapter_name'])
- adapter.add_new_child('node', self.parameters['node_name'])
- try:
- self.server.invoke_successfully(adapter,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error trying to %s fc-adapter %s: %s' % (status, self.parameters['adapter_name'], to_native(e)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- """
- Autosupport log for ucadater
- :return:
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_ucadapter", cserver)
-
- def apply(self):
- ''' calling all adapter features '''
- changed = False
- adapter_detail = self.get_adapter()
-
- def need_to_change(expected, pending, current):
- if expected is None:
- return False
- elif pending is not None:
- return pending != expected
- elif current is not None:
- return current != expected
- return False
-
- if adapter_detail:
- changed = need_to_change(self.parameters.get('type'), adapter_detail['pending-type'],
- adapter_detail['type']) or need_to_change(self.parameters.get('mode'),
- adapter_detail['pending-mode'],
- adapter_detail['mode'])
-
- if changed:
- if self.module.check_mode:
- pass
- else:
- self.online_or_offline_adapter('down')
- self.modify_adapter()
- self.online_or_offline_adapter('up')
-
- self.module.exit_json(changed=changed)
-
-
-def main():
- adapter = NetAppOntapadapter()
- adapter.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_unix_group.py b/lib/ansible/modules/storage/netapp/na_ontap_unix_group.py
deleted file mode 100644
index 2d24b7bdb4..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_unix_group.py
+++ /dev/null
@@ -1,348 +0,0 @@
-#!/usr/bin/python
-"""
-create Autosupport module to enable, disable or modify
-"""
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = """
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - "Create/Delete Unix user group"
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_unix_group
-options:
- state:
- description:
- - Whether the specified group should exist or not.
- choices: ['present', 'absent']
- default: 'present'
-
- name:
- description:
- - Specifies UNIX group's name, unique for each group.
- - Non-modifiable.
- required: true
-
- id:
- description:
- - Specifies an identification number for the UNIX group.
- - Group ID is unique for each UNIX group.
- - Required for create, modifiable.
-
- vserver:
- description:
- - Specifies the Vserver for the UNIX group.
- - Non-modifiable.
- required: true
-
- skip_name_validation:
- description:
- - Specifies if group name validation is skipped.
- type: bool
-
- users:
- description:
- - Specifies the users associated with this group. Should be comma separated.
- - It represents the expected state of a list of users at any time.
- - Add a user into group if it is specified in expected state but not in current state.
- - Delete a user from group if it is specified in current state but not in expected state.
- - To delete all current users, use '' as value.
- type: list
- version_added: "2.9"
-
-short_description: NetApp ONTAP UNIX Group
-version_added: "2.8"
-
-"""
-
-EXAMPLES = """
- - name: Create UNIX group
- na_ontap_unix_group:
- state: present
- name: SampleGroup
- vserver: ansibleVServer
- id: 2
- users: user1,user2
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete all users in UNIX group
- na_ontap_unix_group:
- state: present
- name: SampleGroup
- vserver: ansibleVServer
- users: ''
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete UNIX group
- na_ontap_unix_group:
- state: absent
- name: SampleGroup
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-"""
-
-RETURN = """
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapUnixGroup(object):
- """
- Common operations to manage UNIX groups
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- id=dict(required=False, type='int'),
- skip_name_validation=dict(required=False, type='bool'),
- vserver=dict(required=True, type='str'),
- users=dict(required=False, type='list')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- self.set_playbook_zapi_key_map()
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def set_playbook_zapi_key_map(self):
- self.na_helper.zapi_string_keys = {
- 'name': 'group-name'
- }
- self.na_helper.zapi_int_keys = {
- 'id': 'group-id'
- }
- self.na_helper.zapi_bool_keys = {
- 'skip_name_validation': 'skip-name-validation'
- }
-
- def get_unix_group(self):
- """
- Checks if the UNIX group exists.
-
- :return:
- dict() if group found
- None if group is not found
- """
-
- get_unix_group = netapp_utils.zapi.NaElement('name-mapping-unix-group-get-iter')
- attributes = {
- 'query': {
- 'unix-group-info': {
- 'group-name': self.parameters['name'],
- 'vserver': self.parameters['vserver'],
- }
- }
- }
- get_unix_group.translate_struct(attributes)
- try:
- result = self.server.invoke_successfully(get_unix_group, enable_tunneling=True)
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- group_info = result['attributes-list']['unix-group-info']
- group_details = dict()
- else:
- return None
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting UNIX group %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
- group_details[item_key] = group_info[zapi_key]
- for item_key, zapi_key in self.na_helper.zapi_int_keys.items():
- group_details[item_key] = self.na_helper.get_value_for_int(from_zapi=True,
- value=group_info[zapi_key])
- if group_info.get_child_by_name('users') is not None:
- group_details['users'] = [user.get_child_content('user-name')
- for user in group_info.get_child_by_name('users').get_children()]
- else:
- group_details['users'] = None
- return group_details
-
- def create_unix_group(self):
- """
- Creates an UNIX group in the specified Vserver
-
- :return: None
- """
- if self.parameters.get('id') is None:
- self.module.fail_json(msg='Error: Missing a required parameter for create: (id)')
-
- group_create = netapp_utils.zapi.NaElement('name-mapping-unix-group-create')
- group_details = {}
- for item in self.parameters:
- if item in self.na_helper.zapi_string_keys:
- zapi_key = self.na_helper.zapi_string_keys.get(item)
- group_details[zapi_key] = self.parameters[item]
- elif item in self.na_helper.zapi_bool_keys:
- zapi_key = self.na_helper.zapi_bool_keys.get(item)
- group_details[zapi_key] = self.na_helper.get_value_for_bool(from_zapi=False,
- value=self.parameters[item])
- elif item in self.na_helper.zapi_int_keys:
- zapi_key = self.na_helper.zapi_int_keys.get(item)
- group_details[zapi_key] = self.na_helper.get_value_for_int(from_zapi=True,
- value=self.parameters[item])
- group_create.translate_struct(group_details)
- try:
- self.server.invoke_successfully(group_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating UNIX group %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- if self.parameters.get('users') is not None:
- self.modify_users_in_group()
-
- def delete_unix_group(self):
- """
- Deletes an UNIX group from a vserver
-
- :return: None
- """
- group_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'name-mapping-unix-group-destroy', **{'group-name': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(group_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error removing UNIX group %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_unix_group(self, params):
- """
- Modify an UNIX group from a vserver
- :param params: modify parameters
- :return: None
- """
- # modify users requires separate zapi.
- if 'users' in params:
- self.modify_users_in_group()
- if len(params) == 1:
- return
-
- group_modify = netapp_utils.zapi.NaElement('name-mapping-unix-group-modify')
- group_details = {'group-name': self.parameters['name']}
- for key in params:
- if key in self.na_helper.zapi_int_keys:
- zapi_key = self.na_helper.zapi_int_keys.get(key)
- group_details[zapi_key] = self.na_helper.get_value_for_int(from_zapi=True,
- value=params[key])
- group_modify.translate_struct(group_details)
-
- try:
- self.server.invoke_successfully(group_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying UNIX group %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_users_in_group(self):
- """
- Add/delete one or many users in a UNIX group
-
- :return: None
- """
- current_users = self.get_unix_group().get('users')
- expect_users = self.parameters.get('users')
-
- if current_users is None:
- current_users = []
- if expect_users[0] == '' and len(expect_users) == 1:
- expect_users = []
-
- users_to_remove = list(set(current_users) - set(expect_users))
- users_to_add = list(set(expect_users) - set(current_users))
-
- if len(users_to_add) > 0:
- for user in users_to_add:
- add_user = netapp_utils.zapi.NaElement('name-mapping-unix-group-add-user')
- group_details = {'group-name': self.parameters['name'], 'user-name': user}
- add_user.translate_struct(group_details)
- try:
- self.server.invoke_successfully(add_user, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(
- msg='Error adding user %s to UNIX group %s: %s' % (user, self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- if len(users_to_remove) > 0:
- for user in users_to_remove:
- delete_user = netapp_utils.zapi.NaElement('name-mapping-unix-group-delete-user')
- group_details = {'group-name': self.parameters['name'], 'user-name': user}
- delete_user.translate_struct(group_details)
- try:
- self.server.invoke_successfully(delete_user, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(
- msg='Error deleting user %s from UNIX group %s: %s' % (user, self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- """
- Autosupport log for unix_group
- :return: None
- """
- netapp_utils.ems_log_event("na_ontap_unix_group", self.server)
-
- def apply(self):
- """
- Invoke appropriate action based on playbook parameters
-
- :return: None
- """
- self.autosupport_log()
- current = self.get_unix_group()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if self.parameters['state'] == 'present' and cd_action is None:
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_unix_group()
- elif cd_action == 'delete':
- self.delete_unix_group()
- else:
- self.modify_unix_group(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- obj = NetAppOntapUnixGroup()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_unix_user.py b/lib/ansible/modules/storage/netapp/na_ontap_unix_user.py
deleted file mode 100644
index ee620f47fa..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_unix_user.py
+++ /dev/null
@@ -1,253 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_unix_user
-
-short_description: NetApp ONTAP UNIX users
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create, delete or modify UNIX users local to ONTAP.
-
-options:
-
- state:
- description:
- - Whether the specified user should exist or not.
- choices: ['present', 'absent']
- default: 'present'
-
- name:
- description:
- - Specifies user's UNIX account name.
- - Non-modifiable.
- required: true
-
- group_id:
- description:
- - Specifies the primary group identification number for the UNIX user
- - Required for create, modifiable.
-
- vserver:
- description:
- - Specifies the Vserver for the UNIX user.
- - Non-modifiable.
- required: true
-
- id:
- description:
- - Specifies an identification number for the UNIX user.
- - Required for create, modifiable.
-
- full_name:
- description:
- - Specifies the full name of the UNIX user
- - Optional for create, modifiable.
-'''
-
-EXAMPLES = """
-
- - name: Create UNIX User
- na_ontap_unix_user:
- state: present
- name: SampleUser
- vserver: ansibleVServer
- group_id: 1
- id: 2
- full_name: Test User
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete UNIX User
- na_ontap_unix_user:
- state: absent
- name: SampleUser
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-"""
-
-RETURN = """
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapUnixUser(object):
- """
- Common operations to manage users and roles.
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- group_id=dict(required=False, type='int'),
- id=dict(required=False, type='int'),
- full_name=dict(required=False, type='str'),
- vserver=dict(required=True, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_unix_user(self):
- """
- Checks if the UNIX user exists.
-
- :return:
- dict() if user found
- None if user is not found
- """
-
- get_unix_user = netapp_utils.zapi.NaElement('name-mapping-unix-user-get-iter')
- attributes = {
- 'query': {
- 'unix-user-info': {
- 'user-name': self.parameters['name'],
- 'vserver': self.parameters['vserver'],
- }
- }
- }
- get_unix_user.translate_struct(attributes)
- try:
- result = self.server.invoke_successfully(get_unix_user, enable_tunneling=True)
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- user_info = result['attributes-list']['unix-user-info']
- return {'group_id': int(user_info['group-id']),
- 'id': int(user_info['user-id']),
- 'full_name': user_info['full-name']}
- return None
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting UNIX user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def create_unix_user(self):
- """
- Creates an UNIX user in the specified Vserver
-
- :return: None
- """
- if self.parameters.get('group_id') is None or self.parameters.get('id') is None:
- self.module.fail_json(msg='Error: Missing one or more required parameters for create: (group_id, id)')
-
- user_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'name-mapping-unix-user-create', **{'user-name': self.parameters['name'],
- 'group-id': str(self.parameters['group_id']),
- 'user-id': str(self.parameters['id'])})
- if self.parameters.get('full_name') is not None:
- user_create.add_new_child('full-name', self.parameters['full_name'])
-
- try:
- self.server.invoke_successfully(user_create, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating UNIX user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_unix_user(self):
- """
- Deletes an UNIX user from a vserver
-
- :return: None
- """
- user_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'name-mapping-unix-user-destroy', **{'user-name': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(user_delete, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error removing UNIX user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_unix_user(self, params):
- user_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'name-mapping-unix-user-modify', **{'user-name': self.parameters['name']})
- for key in params:
- if key == 'group_id':
- user_modify.add_new_child('group-id', str(params['group_id']))
- if key == 'id':
- user_modify.add_new_child('user-id', str(params['id']))
- if key == 'full_name':
- user_modify.add_new_child('full-name', params['full_name'])
-
- try:
- self.server.invoke_successfully(user_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying UNIX user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def autosupport_log(self):
- """
- Autosupport log for unix_user
- :return: None
- """
- netapp_utils.ems_log_event("na_ontap_unix_user", self.server)
-
- def apply(self):
- """
- Invoke appropriate action based on playbook parameters
-
- :return: None
- """
- self.autosupport_log()
- current = self.get_unix_user()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if self.parameters['state'] == 'present' and cd_action is None:
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_unix_user()
- elif cd_action == 'delete':
- self.delete_unix_user()
- else:
- self.modify_unix_user(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- obj = NetAppOntapUnixUser()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_user.py b/lib/ansible/modules/storage/netapp/na_ontap_user.py
deleted file mode 100644
index dcb69acffb..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_user.py
+++ /dev/null
@@ -1,389 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_user
-
-short_description: NetApp ONTAP user configuration and management
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create or destroy users.
-
-options:
- state:
- description:
- - Whether the specified user should exist or not.
- choices: ['present', 'absent']
- default: 'present'
- name:
- description:
- - The name of the user to manage.
- required: true
- applications:
- description:
- - List of application to grant access to.
- required: true
- type: list
- choices: ['console', 'http','ontapi','rsh','snmp','service-processor','sp','ssh','telnet']
- aliases:
- - application
- authentication_method:
- description:
- - Authentication method for the application.
- - Not all authentication methods are valid for an application.
- - Valid authentication methods for each application are as denoted in I(authentication_choices_description).
- - Password for console application
- - Password, domain, nsswitch, cert for http application.
- - Password, domain, nsswitch, cert for ontapi application.
- - Community for snmp application (when creating SNMPv1 and SNMPv2 users).
- - The usm and community for snmp application (when creating SNMPv3 users).
- - Password for sp application.
- - Password for rsh application.
- - Password for telnet application.
- - Password, publickey, domain, nsswitch for ssh application.
- required: true
- choices: ['community', 'password', 'publickey', 'domain', 'nsswitch', 'usm', 'cert']
- set_password:
- description:
- - Password for the user account.
- - It is ignored for creating snmp users, but is required for creating non-snmp users.
- - For an existing user, this value will be used as the new password.
- role_name:
- description:
- - The name of the role. Required when C(state=present)
- lock_user:
- description:
- - Whether the specified user account is locked.
- type: bool
- vserver:
- description:
- - The name of the vserver to use.
- required: true
-'''
-
-EXAMPLES = """
-
- - name: Create User
- na_ontap_user:
- state: present
- name: SampleUser
- applications: ssh,console
- authentication_method: password
- set_password: apn1242183u1298u41
- lock_user: True
- role_name: vsadmin
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Delete User
- na_ontap_user:
- state: absent
- name: SampleUser
- applications: ssh
- authentication_method: password
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-"""
-
-RETURN = """
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapUser(object):
- """
- Common operations to manage users and roles.
- """
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
-
- applications=dict(required=True, type='list', aliases=['application'],
- choices=['console', 'http', 'ontapi', 'rsh', 'snmp',
- 'sp', 'service-processor', 'ssh', 'telnet'],),
- authentication_method=dict(required=True, type='str',
- choices=['community', 'password', 'publickey', 'domain', 'nsswitch', 'usm', 'cert']),
- set_password=dict(required=False, type='str', no_log=True),
- role_name=dict(required=False, type='str'),
- lock_user=dict(required=False, type='bool'),
- vserver=dict(required=True, type='str'),
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- required_if=[
- ('state', 'present', ['role_name'])
- ],
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_user(self, application=None):
- """
- Checks if the user exists.
- :param: application: application to grant access to
- :return:
- Dictionary if user found
- None if user is not found
- """
- security_login_get_iter = netapp_utils.zapi.NaElement('security-login-get-iter')
- query_details = netapp_utils.zapi.NaElement.create_node_with_children(
- 'security-login-account-info', **{'vserver': self.parameters['vserver'],
- 'user-name': self.parameters['name'],
- 'authentication-method': self.parameters['authentication_method']})
- if application is not None:
- query_details.add_new_child('application', application)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- security_login_get_iter.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(security_login_get_iter,
- enable_tunneling=False)
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) >= 1:
- interface_attributes = result.get_child_by_name('attributes-list').\
- get_child_by_name('security-login-account-info')
- return_value = {
- 'lock_user': interface_attributes.get_child_content('is-locked'),
- 'role_name': interface_attributes.get_child_content('role-name')
- }
- return return_value
- return None
- except netapp_utils.zapi.NaApiError as error:
- # Error 16034 denotes a user not being found.
- if to_native(error.code) == "16034":
- return None
- # Error 16043 denotes the user existing, but the application missing
- elif to_native(error.code) == "16043":
- return None
- else:
- self.module.fail_json(msg='Error getting user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def create_user(self, application):
- """
- creates the user for the given application and authentication_method
- :param: application: application to grant access to
- """
- user_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'security-login-create', **{'vserver': self.parameters['vserver'],
- 'user-name': self.parameters['name'],
- 'application': application,
- 'authentication-method': self.parameters['authentication_method'],
- 'role-name': self.parameters.get('role_name')})
- if self.parameters.get('set_password') is not None:
- user_create.add_new_child('password', self.parameters.get('set_password'))
-
- try:
- self.server.invoke_successfully(user_create,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def lock_given_user(self):
- """
- locks the user
-
- :return:
- True if user locked
- False if lock user is not performed
- :rtype: bool
- """
- user_lock = netapp_utils.zapi.NaElement.create_node_with_children(
- 'security-login-lock', **{'vserver': self.parameters['vserver'],
- 'user-name': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(user_lock,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error locking user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def unlock_given_user(self):
- """
- unlocks the user
-
- :return:
- True if user unlocked
- False if unlock user is not performed
- :rtype: bool
- """
- user_unlock = netapp_utils.zapi.NaElement.create_node_with_children(
- 'security-login-unlock', **{'vserver': self.parameters['vserver'],
- 'user-name': self.parameters['name']})
-
- try:
- self.server.invoke_successfully(user_unlock,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- if to_native(error.code) == '13114':
- return False
- else:
- self.module.fail_json(msg='Error unlocking user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- return True
-
- def delete_user(self, application):
- """
- deletes the user for the given application and authentication_method
- :param: application: application to grant access to
- """
- user_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'security-login-delete', **{'vserver': self.parameters['vserver'],
- 'user-name': self.parameters['name'],
- 'application': application,
- 'authentication-method': self.parameters['authentication_method']})
-
- try:
- self.server.invoke_successfully(user_delete,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error removing user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def change_password(self):
- """
- Changes the password
-
- :return:
- True if password updated
- False if password is not updated
- :rtype: bool
- """
- # self.server.set_vserver(self.parameters['vserver'])
- modify_password = netapp_utils.zapi.NaElement.create_node_with_children(
- 'security-login-modify-password', **{
- 'new-password': str(self.parameters.get('set_password')),
- 'user-name': self.parameters['name']})
- try:
- self.server.invoke_successfully(modify_password,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- if to_native(error.code) == '13114':
- return False
- # if the user give the same password, instead of returning an error, return ok
- if to_native(error.code) == '13214' and \
- (error.message.startswith('New password must be different than last 6 passwords.')
- or error.message.startswith('New password must be different than the old password.')):
- return False
- self.module.fail_json(msg='Error setting password for user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- self.server.set_vserver(None)
- return True
-
- def modify_user(self, application):
- """
- Modify user
- """
- user_modify = netapp_utils.zapi.NaElement.create_node_with_children(
- 'security-login-modify', **{'vserver': self.parameters['vserver'],
- 'user-name': self.parameters['name'],
- 'application': application,
- 'authentication-method': self.parameters['authentication_method'],
- 'role-name': self.parameters.get('role_name')})
-
- try:
- self.server.invoke_successfully(user_modify,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying user %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- create_delete_decision = {}
- modify_decision = {}
-
- netapp_utils.ems_log_event("na_ontap_user", self.server)
- for application in self.parameters['applications']:
- current = self.get_user(application)
- if current is not None:
- current['lock_user'] = self.na_helper.get_value_for_bool(True, current['lock_user'])
-
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
-
- if cd_action is not None:
- create_delete_decision[application] = cd_action
- else:
- modify_decision[application] = self.na_helper.get_modified_attributes(current, self.parameters)
-
- if not create_delete_decision and self.parameters.get('state') == 'present':
- if self.parameters.get('set_password') is not None:
- self.na_helper.changed = True
-
- if self.na_helper.changed:
-
- if self.module.check_mode:
- pass
- else:
- for application in create_delete_decision:
- if create_delete_decision[application] == 'create':
- self.create_user(application)
- elif create_delete_decision[application] == 'delete':
- self.delete_user(application)
- lock_user = False
- for application in modify_decision:
- if 'role_name' in modify_decision[application]:
- self.modify_user(application)
- if 'lock_user' in modify_decision[application]:
- lock_user = True
-
- if lock_user:
- if self.parameters.get('lock_user'):
- self.lock_given_user()
- else:
- self.unlock_given_user()
- if not create_delete_decision and self.parameters.get('set_password') is not None:
- # if change password return false nothing has changed so we need to set changed to False
- self.na_helper.changed = self.change_password()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- obj = NetAppOntapUser()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_user_role.py b/lib/ansible/modules/storage/netapp/na_ontap_user_role.py
deleted file mode 100644
index 167e78529d..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_user_role.py
+++ /dev/null
@@ -1,268 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_user_role
-
-short_description: NetApp ONTAP user role configuration and management
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create or destroy user roles
-
-options:
-
- state:
- description:
- - Whether the specified user should exist or not.
- choices: ['present', 'absent']
- default: present
-
- name:
- description:
- - The name of the role to manage.
- required: true
-
- command_directory_name:
- description:
- - The command or command directory to which the role has an access.
- required: true
-
- access_level:
- description:
- - The name of the role to manage.
- choices: ['none', 'readonly', 'all']
- default: all
-
- query:
- description:
- - A query for the role. The query must apply to the specified command or directory name.
- - Use double quotes "" for modifying a existing query to none.
- version_added: '2.8'
-
- vserver:
- description:
- - The name of the vserver to use.
- required: true
-
-'''
-
-EXAMPLES = """
-
- - name: Create User Role
- na_ontap_user_role:
- state: present
- name: ansibleRole
- command_directory_name: volume
- access_level: none
- query: show
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Modify User Role
- na_ontap_user_role:
- state: present
- name: ansibleRole
- command_directory_name: volume
- access_level: none
- query: ""
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
-"""
-
-RETURN = """
-
-"""
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-from ansible.module_utils.netapp_module import NetAppModule
-import ansible.module_utils.netapp as netapp_utils
-
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapUserRole(object):
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- command_directory_name=dict(required=True, type='str'),
- access_level=dict(required=False, type='str', default='all',
- choices=['none', 'readonly', 'all']),
- vserver=dict(required=True, type='str'),
- query=dict(required=False, type='str')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_role(self):
- """
- Checks if the role exists for specific command-directory-name.
-
- :return:
- True if role found
- False if role is not found
- :rtype: bool
- """
- options = {'vserver': self.parameters['vserver'],
- 'role-name': self.parameters['name'],
- 'command-directory-name': self.parameters['command_directory_name']}
-
- security_login_role_get_iter = netapp_utils.zapi.NaElement(
- 'security-login-role-get-iter')
- query_details = netapp_utils.zapi.NaElement.create_node_with_children(
- 'security-login-role-info', **options)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(query_details)
- security_login_role_get_iter.add_child_elem(query)
-
- try:
- result = self.server.invoke_successfully(
- security_login_role_get_iter, enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as e:
- # Error 16031 denotes a role not being found.
- if to_native(e.code) == "16031":
- return None
- # Error 16039 denotes command directory not found.
- elif to_native(e.code) == "16039":
- return None
- else:
- self.module.fail_json(msg='Error getting role %s: %s' % (self.name, to_native(e)),
- exception=traceback.format_exc())
- if (result.get_child_by_name('num-records') and
- int(result.get_child_content('num-records')) >= 1):
- role_info = result.get_child_by_name('attributes-list').get_child_by_name('security-login-role-info')
- result = {
- 'name': role_info['role-name'],
- 'access_level': role_info['access-level'],
- 'command_directory_name': role_info['command-directory-name'],
- 'query': role_info['role-query']
- }
- return result
-
- return None
-
- def create_role(self):
- options = {'vserver': self.parameters['vserver'],
- 'role-name': self.parameters['name'],
- 'command-directory-name': self.parameters['command_directory_name'],
- 'access-level': self.parameters['access_level']}
- if self.parameters.get('query'):
- options['role-query'] = self.parameters['query']
- role_create = netapp_utils.zapi.NaElement.create_node_with_children('security-login-role-create', **options)
-
- try:
- self.server.invoke_successfully(role_create,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating role %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_role(self):
- role_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'security-login-role-delete', **{'vserver': self.parameters['vserver'],
- 'role-name': self.parameters['name'],
- 'command-directory-name':
- self.parameters['command_directory_name']})
-
- try:
- self.server.invoke_successfully(role_delete,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error removing role %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_role(self, modify):
- options = {'vserver': self.parameters['vserver'],
- 'role-name': self.parameters['name'],
- 'command-directory-name': self.parameters['command_directory_name']}
- if 'access_level' in modify.keys():
- options['access-level'] = self.parameters['access_level']
- if 'query' in modify.keys():
- options['role-query'] = self.parameters['query']
-
- role_modify = netapp_utils.zapi.NaElement.create_node_with_children('security-login-role-modify', **options)
-
- try:
- self.server.invoke_successfully(role_modify,
- enable_tunneling=False)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying role %s: %s' % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- self.asup_log_for_cserver('na_ontap_user_role')
- current = self.get_role()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
-
- # if desired state specify empty quote query and current query is None, set desired query to None.
- # otherwise na_helper.get_modified_attributes will detect a change.
- if self.parameters.get('query') == '' and current is not None:
- if current['query'] is None:
- self.parameters['query'] = None
-
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_role()
- elif cd_action == 'delete':
- self.delete_role()
- elif modify:
- self.modify_role(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- netapp_utils.ems_log_event(event_name, self.server)
-
-
-def main():
- obj = NetAppOntapUserRole()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_volume.py b/lib/ansible/modules/storage/netapp/na_ontap_volume.py
deleted file mode 100644
index 9c04b28e0f..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_volume.py
+++ /dev/null
@@ -1,1283 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-
-module: na_ontap_volume
-
-short_description: NetApp ONTAP manage volumes.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
-- Create or destroy or modify volumes on NetApp ONTAP.
-
-options:
-
- state:
- description:
- - Whether the specified volume should exist or not.
- choices: ['present', 'absent']
- default: 'present'
-
- name:
- description:
- - The name of the volume to manage.
- type: str
- required: true
-
- vserver:
- description:
- - Name of the vserver to use.
- type: str
- required: true
-
- from_name:
- description:
- - Name of the existing volume to be renamed to name.
- type: str
- version_added: '2.7'
-
- is_infinite:
- type: bool
- description:
- Set True if the volume is an Infinite Volume.
- Deleting an infinite volume is asynchronous.
-
- is_online:
- type: bool
- description:
- - Whether the specified volume is online, or not.
- default: True
-
- aggregate_name:
- description:
- - The name of the aggregate the flexvol should exist on.
- - Required when C(state=present).
- type: str
-
- size:
- description:
- - The size of the volume in (size_unit). Required when C(state=present).
- type: int
-
- size_unit:
- description:
- - The unit used to interpret the size parameter.
- choices: ['bytes', 'b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb']
- type: str
- default: 'gb'
-
- type:
- description:
- - The volume type, either read-write (RW) or data-protection (DP).
- type: str
-
- policy:
- description:
- - Name of the export policy.
- type: str
-
- junction_path:
- description:
- - Junction path of the volume.
- - To unmount, use junction path C('').
- type: str
-
- space_guarantee:
- description:
- - Space guarantee style for the volume.
- choices: ['none', 'file', 'volume']
- type: str
-
- percent_snapshot_space:
- description:
- - Amount of space reserved for snapshot copies of the volume.
- type: int
-
- volume_security_style:
- description:
- - The security style associated with this volume.
- choices: ['mixed', 'ntfs', 'unified', 'unix']
- default: 'mixed'
- type: str
-
- encrypt:
- type: bool
- description:
- - Whether or not to enable Volume Encryption.
- default: False
- version_added: '2.7'
-
- efficiency_policy:
- description:
- - Allows a storage efficiency policy to be set on volume creation.
- type: str
- version_added: '2.7'
-
- unix_permissions:
- description:
- - Unix permission bits in octal or symbolic format.
- - For example, 0 is equivalent to ------------, 777 is equivalent to ---rwxrwxrwx,both formats are accepted.
- - The valid octal value ranges between 0 and 777 inclusive.
- type: str
- version_added: '2.8'
-
- snapshot_policy:
- description:
- - The name of the snapshot policy.
- - the default policy name is 'default'.
- type: str
- version_added: '2.8'
-
- aggr_list:
- description:
- - an array of names of aggregates to be used for FlexGroup constituents.
- type: list
- version_added: '2.8'
-
- aggr_list_multiplier:
- description:
- - The number of times to iterate over the aggregates listed with the aggr_list parameter when creating a FlexGroup.
- type: int
- version_added: '2.8'
-
- auto_provision_as:
- description:
- - Automatically provision a FlexGroup volume.
- version_added: '2.8'
- choices: ['flexgroup']
- type: str
-
- snapdir_access:
- description:
- - This is an advanced option, the default is False.
- - Enable the visible '.snapshot' directory that is normally present at system internal mount points.
- - This value also turns on access to all other '.snapshot' directories in the volume.
- type: bool
- version_added: '2.8'
-
- atime_update:
- description:
- - This is an advanced option, the default is True.
- - If false, prevent the update of inode access times when a file is read.
- - This value is useful for volumes with extremely high read traffic,
- since it prevents writes to the inode file for the volume from contending with reads from other files.
- - This field should be used carefully.
- - That is, use this field when you know in advance that the correct access time for inodes will not be needed for files on that volume.
- type: bool
- version_added: '2.8'
-
- wait_for_completion:
- description:
- - Set this parameter to 'true' for synchronous execution during create (wait until volume status is online)
- - Set this parameter to 'false' for asynchronous execution
- - For asynchronous, execution exits as soon as the request is sent, without checking volume status
- type: bool
- default: false
- version_added: '2.8'
-
- time_out:
- description:
- - time to wait for flexGroup creation, modification, or deletion in seconds.
- - Error out if task is not completed in defined time.
- - if 0, the request is asynchronous.
- - default is set to 3 minutes.
- default: 180
- type: int
- version_added: '2.8'
-
- language:
- description:
- - Language to use for Volume
- - Default uses SVM language
- - Possible values Language
- - c POSIX
- - ar Arabic
- - cs Czech
- - da Danish
- - de German
- - en English
- - en_us English (US)
- - es Spanish
- - fi Finnish
- - fr French
- - he Hebrew
- - hr Croatian
- - hu Hungarian
- - it Italian
- - ja Japanese euc-j
- - ja_v1 Japanese euc-j
- - ja_jp.pck Japanese PCK (sjis)
- - ja_jp.932 Japanese cp932
- - ja_jp.pck_v2 Japanese PCK (sjis)
- - ko Korean
- - no Norwegian
- - nl Dutch
- - pl Polish
- - pt Portuguese
- - ro Romanian
- - ru Russian
- - sk Slovak
- - sl Slovenian
- - sv Swedish
- - tr Turkish
- - zh Simplified Chinese
- - zh.gbk Simplified Chinese (GBK)
- - zh_tw Traditional Chinese euc-tw
- - zh_tw.big5 Traditional Chinese Big 5
- - To use UTF-8 as the NFS character set, append '.UTF-8' to the language code
- type: str
- version_added: '2.8'
-
- qos_policy_group:
- description:
- - Specifies a QoS policy group to be set on volume.
- version_added: '2.9'
-
- qos_adaptive_policy_group:
- description:
- - Specifies a QoS adaptive policy group to be set on volume.
- version_added: '2.9'
-
- tiering_policy:
- description:
- - The tiering policy that is to be associated with the volume.
- - This policy decides whether the blocks of a volume will be tiered to the capacity tier.
- - snapshot-only policy allows tiering of only the volume snapshot copies not associated with the active file system.
- - auto policy allows tiering of both snapshot and active file system user data to the capacity tier.
- - backup policy on DP volumes allows all transferred user data blocks to start in the capacity tier.
- - When set to none, the Volume blocks will not be tiered to the capacity tier.
- - If no value specified, the volume is assigned snapshot only by default.
- choices: ['snapshot-only', 'auto', 'backup', 'none']
- type: str
- version_added: '2.9'
-
- space_slo:
- description:
- - Specifies the space SLO type for the volume. The space SLO type is the Service Level Objective for space management for the volume.
- - The space SLO value is used to enforce existing volume settings so that sufficient space is set aside on the aggregate to meet the space SLO.
- - This parameter is not supported on Infinite Volumes.
- choices: ['none', 'thick', 'semi-thick']
- type: str
- version_added: '2.9'
-
- nvfail_enabled:
- description:
- - If true, the controller performs additional work at boot and takeover times if it finds that there has been any potential data loss in the volume's
- constituents due to an NVRAM failure.
- - The volume's constituents would be put in a special state called 'in-nvfailed-state' such that protocol access is blocked.
- - This will cause the client applications to crash and thus prevent access to stale data.
- - To get out of this situation, the admin needs to manually clear the 'in-nvfailed-state' on the volume's constituents.
- type: bool
- version_added: '2.9'
-
- vserver_dr_protection:
- description:
- - Specifies the protection type for the volume in a Vserver DR setup.
- choices: ['protected', 'unprotected']
- type: str
- version_added: '2.9'
-
- comment:
- description:
- - Sets a comment associated with the volume.
- type: str
- version_added: '2.9'
-'''
-
-EXAMPLES = """
-
- - name: Create FlexVol
- na_ontap_volume:
- state: present
- name: ansibleVolume12
- is_infinite: False
- aggregate_name: ansible_aggr
- size: 100
- size_unit: mb
- space_guarantee: none
- tiering_policy: auto
- policy: default
- percent_snapshot_space: 60
- qos_policy_group: max_performance_gold
- vserver: ansibleVServer
- wait_for_completion: True
- space_slo: none
- nvfail_enabled: False
- comment: ansible created volume
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Volume Delete
- na_ontap_volume:
- state: absent
- name: ansibleVolume12
- aggregate_name: ansible_aggr
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Make FlexVol offline
- na_ontap_volume:
- state: present
- name: ansibleVolume
- is_infinite: False
- is_online: False
- vserver: ansibleVServer
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Create flexGroup volume manually
- na_ontap_volume:
- state: present
- name: ansibleVolume
- is_infinite: False
- aggr_list: "{{ aggr_list }}"
- aggr_list_multiplier: 2
- size: 200
- size_unit: mb
- space_guarantee: none
- policy: default
- vserver: "{{ vserver }}"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- https: False
- unix_permissions: 777
- snapshot_policy: default
- time_out: 0
-
- - name: Create flexGroup volume auto provision as flex group
- na_ontap_volume:
- state: present
- name: ansibleVolume
- is_infinite: False
- auto_provision_as: flexgroup
- size: 200
- size_unit: mb
- space_guarantee: none
- policy: default
- vserver: "{{ vserver }}"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- https: False
- unix_permissions: 777
- snapshot_policy: default
- time_out: 0
-
- - name: Create FlexVol with QoS adaptive
- na_ontap_volume:
- state: present
- name: ansibleVolume15
- is_infinite: False
- aggregate_name: ansible_aggr
- size: 100
- size_unit: gb
- space_guarantee: none
- policy: default
- percent_snapshot_space: 10
- qos_adaptive_policy_group: extreme
- vserver: ansibleVServer
- wait_for_completion: True
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-
- - name: Modify volume dr protection (vserver of the volume must be in a snapmirror relationship)
- na_ontap_volume:
- state: present
- name: ansibleVolume
- vserver_dr_protection: protected
- vserver: "{{ vserver }}"
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- https: False
-
-"""
-
-RETURN = """
-"""
-
-import time
-import traceback
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapVolume(object):
- '''Class with volume operations'''
-
- def __init__(self):
- '''Initialize module parameters'''
- self._size_unit_map = dict(
- bytes=1,
- b=1,
- kb=1024,
- mb=1024 ** 2,
- gb=1024 ** 3,
- tb=1024 ** 4,
- pb=1024 ** 5,
- eb=1024 ** 6,
- zb=1024 ** 7,
- yb=1024 ** 8
- )
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=[
- 'present', 'absent'], default='present'),
- name=dict(required=True, type='str'),
- vserver=dict(required=True, type='str'),
- from_name=dict(required=False, type='str'),
- is_infinite=dict(required=False, type='bool',
- default=False),
- is_online=dict(required=False, type='bool',
- default=True),
- size=dict(type='int', default=None),
- size_unit=dict(default='gb',
- choices=['bytes', 'b', 'kb', 'mb', 'gb', 'tb',
- 'pb', 'eb', 'zb', 'yb'], type='str'),
- aggregate_name=dict(type='str', default=None),
- type=dict(type='str', default=None),
- policy=dict(type='str', default=None),
- junction_path=dict(type='str', default=None),
- space_guarantee=dict(choices=['none', 'file', 'volume'], default=None),
- percent_snapshot_space=dict(type='int', default=None),
- volume_security_style=dict(choices=['mixed',
- 'ntfs', 'unified', 'unix'],
- default='mixed'),
- encrypt=dict(required=False, type='bool', default=False),
- efficiency_policy=dict(required=False, type='str'),
- unix_permissions=dict(required=False, type='str'),
- snapshot_policy=dict(required=False, type='str'),
- aggr_list=dict(required=False, type='list'),
- aggr_list_multiplier=dict(required=False, type='int'),
- snapdir_access=dict(required=False, type='bool'),
- atime_update=dict(required=False, type='bool'),
- auto_provision_as=dict(choices=['flexgroup'], required=False, type='str'),
- wait_for_completion=dict(required=False, type='bool', default=False),
- time_out=dict(required=False, type='int', default=180),
- language=dict(type='str', required=False),
- qos_policy_group=dict(required=False, type='str'),
- qos_adaptive_policy_group=dict(required=False, type='str'),
- nvfail_enabled=dict(type='bool', required=False),
- space_slo=dict(type='str', required=False, choices=['none', 'thick', 'semi-thick']),
- tiering_policy=dict(type='str', required=False, choices=['snapshot-only', 'auto',
- 'backup', 'none']),
- vserver_dr_protection=dict(type='str', required=False, choices=['protected', 'unprotected']),
- comment=dict(type='str', required=False)
-
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- self.volume_style = None
-
- if self.parameters.get('size'):
- self.parameters['size'] = self.parameters['size'] * \
- self._size_unit_map[self.parameters['size_unit']]
- # ONTAP will return True and False as the string true and false.
- if 'snapdir_access' in self.parameters:
- self.parameters['snapdir_access'] = str(self.parameters['snapdir_access']).lower()
- if 'atime_update' in self.parameters:
- self.parameters['atime_update'] = str(self.parameters['atime_update']).lower()
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(
- msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(
- module=self.module, vserver=self.parameters['vserver'])
- self.cluster = netapp_utils.setup_na_ontap_zapi(module=self.module)
-
- def volume_get_iter(self, vol_name=None):
- """
- Return volume-get-iter query results
- :param vol_name: name of the volume
- :return: NaElement
- """
- volume_info = netapp_utils.zapi.NaElement('volume-get-iter')
- volume_attributes = netapp_utils.zapi.NaElement('volume-attributes')
- volume_id_attributes = netapp_utils.zapi.NaElement('volume-id-attributes')
- volume_id_attributes.add_new_child('name', vol_name)
- volume_id_attributes.add_new_child('vserver', self.parameters['vserver'])
- volume_attributes.add_child_elem(volume_id_attributes)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(volume_attributes)
- volume_info.add_child_elem(query)
-
- try:
- result = self.server.invoke_successfully(volume_info, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching volume %s : %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- return result
-
- def get_volume(self, vol_name=None):
- """
- Return details about the volume
- :param:
- name : Name of the volume
- :return: Details about the volume. None if not found.
- :rtype: dict
- """
- if vol_name is None:
- vol_name = self.parameters['name']
- volume_get_iter = self.volume_get_iter(vol_name)
- return_value = None
- if volume_get_iter.get_child_by_name('num-records') and \
- int(volume_get_iter.get_child_content('num-records')) > 0:
-
- volume_attributes = volume_get_iter['attributes-list']['volume-attributes']
- volume_space_attributes = volume_attributes['volume-space-attributes']
- volume_state_attributes = volume_attributes['volume-state-attributes']
- volume_id_attributes = volume_attributes['volume-id-attributes']
- volume_export_attributes = volume_attributes['volume-export-attributes']
- volume_security_unix_attributes = volume_attributes['volume-security-attributes']['volume-security-unix-attributes']
- volume_snapshot_attributes = volume_attributes['volume-snapshot-attributes']
- volume_performance_attributes = volume_attributes['volume-performance-attributes']
- volume_comp_aggr_attributes = volume_attributes['volume-comp-aggr-attributes']
- # Get volume's state (online/offline)
- current_state = volume_state_attributes['state']
- is_online = (current_state == "online")
-
- return_value = {
- 'name': vol_name,
- 'size': int(volume_space_attributes['size']),
- 'is_online': is_online,
- 'policy': volume_export_attributes['policy'],
- 'unix_permissions': volume_security_unix_attributes['permissions'],
- 'snapshot_policy': volume_snapshot_attributes['snapshot-policy'],
- 'tiering_policy': volume_comp_aggr_attributes['tiering-policy']
- }
- if volume_space_attributes.get_child_by_name('encrypt'):
- return_value['encrypt'] = volume_attributes['encrypt']
- if volume_space_attributes.get_child_by_name('percentage-snapshot-reserve'):
- return_value['percent_snapshot_space'] = int(volume_space_attributes['percentage-snapshot-reserve'])
- if volume_space_attributes.get_child_by_name('space-slo'):
- return_value['space_slo'] = volume_space_attributes['space-slo']
- else:
- return_value['space_slo'] = None
- if volume_state_attributes.get_child_by_name('is-nvfail-enabled') is not None:
- return_value['nvfail_enabled'] = volume_state_attributes['is-nvfail-enabled'] == 'true'
- else:
- return_value['nvfail_enabled'] = None
- if volume_id_attributes.get_child_by_name('containing-aggregate-name'):
- return_value['aggregate_name'] = volume_id_attributes['containing-aggregate-name']
- else:
- return_value['aggregate_name'] = None
- if volume_id_attributes.get_child_by_name('junction-path'):
- return_value['junction_path'] = volume_id_attributes['junction-path']
- else:
- return_value['junction_path'] = ''
- if volume_id_attributes.get_child_by_name('comment'):
- return_value['comment'] = volume_id_attributes['comment']
- else:
- return_value['comment'] = None
- if volume_id_attributes.get_child_by_name('style-extended'):
- return_value['style_extended'] = volume_id_attributes['style-extended']
- else:
- return_value['style_extended'] = None
- if volume_space_attributes.get_child_by_name('space-guarantee'):
- return_value['space_guarantee'] = volume_space_attributes['space-guarantee']
- else:
- return_value['space_guarantee'] = None
- if volume_snapshot_attributes.get_child_by_name('snapdir-access-enabled'):
- return_value['snapdir_access'] = volume_snapshot_attributes['snapdir-access-enabled']
- else:
- return_value['snapdir_access'] = None
- if volume_performance_attributes.get_child_by_name('is-atime-update-enabled'):
- return_value['atime_update'] = volume_performance_attributes['is-atime-update-enabled']
- else:
- return_value['atime_update'] = None
- if volume_attributes.get_child_by_name('volume-qos-attributes'):
- volume_qos_attributes = volume_attributes['volume-qos-attributes']
- if volume_qos_attributes.get_child_by_name('policy-group-name'):
- return_value['qos_policy_group'] = volume_qos_attributes['policy-group-name']
- else:
- return_value['qos_policy_group'] = None
- if volume_qos_attributes.get_child_by_name('adaptive-policy-group-name'):
- return_value['qos_adaptive_policy_group'] = volume_qos_attributes['adaptive-policy-group-name']
- else:
- return_value['qos_adaptive_policy_group'] = None
- else:
- return_value['qos_policy_group'] = None
- return_value['qos_adaptive_policy_group'] = None
- if volume_attributes.get_child_by_name('volume-vserver-dr-protection-attributes'):
- volume_vserver_dr_protection_attributes = volume_attributes['volume-vserver-dr-protection-attributes']
- if volume_vserver_dr_protection_attributes.get_child_by_name('vserver-dr-protection'):
- return_value['vserver_dr_protection'] = volume_vserver_dr_protection_attributes['vserver-dr-protection']
- else:
- return_value['vserver_dr_protection'] = None
-
- return return_value
-
- def create_volume(self):
- '''Create ONTAP volume'''
- if self.volume_style == 'flexGroup':
- self.create_volume_async()
- else:
- options = self.create_volume_options()
- volume_create = netapp_utils.zapi.NaElement.create_node_with_children('volume-create', **options)
- try:
- self.server.invoke_successfully(volume_create, enable_tunneling=True)
- if self.parameters.get('wait_for_completion'):
- # round off time_out
- retries = (self.parameters['time_out'] + 5) // 10
- current = self.get_volume()
- is_online = None if current is None else current['is_online']
- while not is_online and retries > 0:
- time.sleep(10)
- retries = retries - 1
- current = self.get_volume()
- is_online = None if current is None else current['is_online']
- self.ems_log_event("volume-create")
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error provisioning volume %s of size %s: %s'
- % (self.parameters['name'], self.parameters['size'], to_native(error)),
- exception=traceback.format_exc())
-
- if self.parameters.get('efficiency_policy'):
- self.assign_efficiency_policy()
-
- def create_volume_async(self):
- '''
- create volume async.
- '''
- options = self.create_volume_options()
- volume_create = netapp_utils.zapi.NaElement.create_node_with_children('volume-create-async', **options)
- if self.parameters.get('aggr_list'):
- aggr_list_obj = netapp_utils.zapi.NaElement('aggr-list')
- volume_create.add_child_elem(aggr_list_obj)
- for aggr in self.parameters['aggr_list']:
- aggr_list_obj.add_new_child('aggr-name', aggr)
- try:
- result = self.server.invoke_successfully(volume_create, enable_tunneling=True)
- self.ems_log_event("volume-create")
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error provisioning volume %s of size %s: %s'
- % (self.parameters['name'], self.parameters['size'], to_native(error)),
- exception=traceback.format_exc())
- self.check_invoke_result(result, 'create')
-
- if self.parameters.get('efficiency_policy'):
- self.assign_efficiency_policy_async()
-
- def create_volume_options(self):
- '''Set volume options for create operation'''
- options = {}
- if self.volume_style == 'flexGroup':
- options['volume-name'] = self.parameters['name']
- if self.parameters.get('aggr_list_multiplier'):
- options['aggr-list-multiplier'] = str(self.parameters['aggr_list_multiplier'])
- if self.parameters.get('auto_provision_as'):
- options['auto-provision-as'] = self.parameters['auto_provision_as']
- if self.parameters.get('space_guarantee'):
- options['space-guarantee'] = self.parameters['space_guarantee']
- else:
- options['volume'] = self.parameters['name']
- if self.parameters.get('aggregate_name') is None:
- self.module.fail_json(msg='Error provisioning volume %s: aggregate_name is required'
- % self.parameters['name'])
- options['containing-aggr-name'] = self.parameters['aggregate_name']
- if self.parameters.get('space_guarantee'):
- options['space-reserve'] = self.parameters['space_guarantee']
-
- if self.parameters.get('size'):
- options['size'] = str(self.parameters['size'])
- if self.parameters.get('snapshot_policy'):
- options['snapshot-policy'] = self.parameters['snapshot_policy']
- if self.parameters.get('unix_permissions'):
- options['unix-permissions'] = self.parameters['unix_permissions']
- if self.parameters.get('volume_security_style'):
- options['volume-security-style'] = self.parameters['volume_security_style']
- if self.parameters.get('policy'):
- options['export-policy'] = self.parameters['policy']
- if self.parameters.get('junction_path'):
- options['junction-path'] = self.parameters['junction_path']
- if self.parameters.get('comment'):
- options['volume-comment'] = self.parameters['comment']
- if self.parameters.get('type'):
- options['volume-type'] = self.parameters['type']
- if self.parameters.get('percent_snapshot_space') is not None:
- options['percentage-snapshot-reserve'] = str(self.parameters['percent_snapshot_space'])
- if self.parameters.get('language'):
- options['language-code'] = self.parameters['language']
- if self.parameters.get('qos_policy_group'):
- options['qos-policy-group-name'] = self.parameters['qos_policy_group']
- if self.parameters.get('qos_adaptive_policy_group'):
- options['qos-adaptive-policy-group-name'] = self.parameters['qos_adaptive_policy_group']
- if self.parameters.get('nvfail_enabled') is not None:
- options['is-nvfail-enabled'] = str(self.parameters['nvfail_enabled'])
- if self.parameters.get('space_slo'):
- options['space-slo'] = self.parameters['space_slo']
- if self.parameters.get('tiering_policy'):
- options['tiering-policy'] = self.parameters['tiering_policy']
- if self.parameters.get('encrypt'):
- options['encrypt'] = str(self.parameters['encrypt'])
- if self.parameters.get('vserver_dr_protection'):
- options['vserver-dr-protection'] = self.parameters['vserver_dr_protection']
- return options
-
- def delete_volume(self):
- '''Delete ONTAP volume'''
- if self.parameters.get('is_infinite') or self.volume_style == 'flexGroup':
- volume_delete = netapp_utils.zapi\
- .NaElement.create_node_with_children(
- 'volume-destroy-async', **{'volume-name': self.parameters['name'], 'unmount-and-offline': 'true'})
- else:
- volume_delete = netapp_utils.zapi\
- .NaElement.create_node_with_children(
- 'volume-destroy', **{'name': self.parameters['name'],
- 'unmount-and-offline': 'true'})
- try:
- result = self.server.invoke_successfully(volume_delete, enable_tunneling=True)
- if self.parameters.get('is_infinite') or self.volume_style == 'flexGroup':
- self.check_invoke_result(result, 'delete')
- self.ems_log_event("volume-delete")
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting volume %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def move_volume(self):
- '''Move volume from source aggregate to destination aggregate'''
- volume_move = netapp_utils.zapi.NaElement.create_node_with_children(
- 'volume-move-start', **{'source-volume': self.parameters['name'],
- 'vserver': self.parameters['vserver'],
- 'dest-aggr': self.parameters['aggregate_name']})
- try:
- self.cluster.invoke_successfully(volume_move,
- enable_tunneling=True)
- self.ems_log_event("volume-move")
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error moving volume %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def rename_volume(self):
- """
- Rename the volume.
-
- Note: 'is_infinite' needs to be set to True in order to rename an
- Infinite Volume. Use time_out parameter to set wait time for rename completion.
- """
- vol_rename_zapi, vol_name_zapi = ['volume-rename-async', 'volume-name'] if self.parameters['is_infinite']\
- else ['volume-rename', 'volume']
- volume_rename = netapp_utils.zapi.NaElement.create_node_with_children(
- vol_rename_zapi, **{vol_name_zapi: self.parameters['from_name'],
- 'new-volume-name': str(self.parameters['name'])})
- try:
- result = self.server.invoke_successfully(volume_rename, enable_tunneling=True)
- if vol_rename_zapi == 'volume-rename-async':
- self.check_invoke_result(result, 'rename')
- self.ems_log_event("volume-rename")
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error renaming volume %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def resize_volume(self):
- """
- Re-size the volume.
-
- Note: 'is_infinite' needs to be set to True in order to rename an
- Infinite Volume.
- """
- vol_size_zapi, vol_name_zapi = ['volume-size-async', 'volume-name']\
- if (self.parameters['is_infinite'] or self.volume_style == 'flexGroup')\
- else ['volume-size', 'volume']
- volume_resize = netapp_utils.zapi.NaElement.create_node_with_children(
- vol_size_zapi, **{vol_name_zapi: self.parameters['name'],
- 'new-size': str(self.parameters['size'])})
- try:
- result = self.server.invoke_successfully(volume_resize, enable_tunneling=True)
- if vol_size_zapi == 'volume-size-async':
- self.check_invoke_result(result, 'resize')
- self.ems_log_event("volume-resize")
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error re-sizing volume %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def change_volume_state(self):
- """
- Change volume's state (offline/online).
- """
- if self.parameters['is_online']: # Desired state is online, setup zapi APIs respectively
- vol_state_zapi, vol_name_zapi, action = ['volume-online-async', 'volume-name', 'online']\
- if (self.parameters['is_infinite'] or self.volume_style == 'flexGroup')\
- else ['volume-online', 'name', 'online']
- else: # Desired state is offline, setup zapi APIs respectively
- vol_state_zapi, vol_name_zapi, action = ['volume-offline-async', 'volume-name', 'offline']\
- if (self.parameters['is_infinite'] or self.volume_style == 'flexGroup')\
- else ['volume-offline', 'name', 'offline']
- volume_unmount = netapp_utils.zapi.NaElement.create_node_with_children(
- 'volume-unmount', **{'volume-name': self.parameters['name']})
- volume_change_state = netapp_utils.zapi.NaElement.create_node_with_children(
- vol_state_zapi, **{vol_name_zapi: self.parameters['name']})
- try:
- if not self.parameters['is_online']: # Unmount before offline
- self.server.invoke_successfully(volume_unmount, enable_tunneling=True)
- result = self.server.invoke_successfully(volume_change_state, enable_tunneling=True)
- if self.volume_style == 'flexGroup' or self.parameters['is_infinite']:
- self.check_invoke_result(result, action)
- self.ems_log_event("change-state")
- except netapp_utils.zapi.NaApiError as error:
- state = "online" if self.parameters['is_online'] else "offline"
- self.module.fail_json(msg='Error changing the state of volume %s to %s: %s'
- % (self.parameters['name'], state, to_native(error)),
- exception=traceback.format_exc())
-
- def create_volume_attribute(self, zapi_object, parent_attribute, attribute, value):
- """
-
- :param parent_attribute:
- :param child_attribute:
- :param value:
- :return:
- """
- if isinstance(parent_attribute, str):
- vol_attribute = netapp_utils.zapi.NaElement(parent_attribute)
- vol_attribute.add_new_child(attribute, value)
- zapi_object.add_child_elem(vol_attribute)
- else:
- zapi_object.add_new_child(attribute, value)
- parent_attribute.add_child_elem(zapi_object)
-
- def volume_modify_attributes(self, params):
- """
- modify volume parameter 'policy','unix_permissions','snapshot_policy','space_guarantee', 'percent_snapshot_space',
- 'qos_policy_group', 'qos_adaptive_policy_group'
- """
- # TODO: refactor this method
- if self.volume_style == 'flexGroup' or self.parameters['is_infinite']:
- vol_mod_iter = netapp_utils.zapi.NaElement('volume-modify-iter-async')
- else:
- vol_mod_iter = netapp_utils.zapi.NaElement('volume-modify-iter')
- attributes = netapp_utils.zapi.NaElement('attributes')
- vol_mod_attributes = netapp_utils.zapi.NaElement('volume-attributes')
- # Volume-attributes is split in to 25 sub categories
- # volume-space-attributes
- vol_space_attributes = netapp_utils.zapi.NaElement('volume-space-attributes')
- if self.parameters.get('space_guarantee'):
- self.create_volume_attribute(vol_space_attributes, vol_mod_attributes,
- 'space-guarantee', self.parameters['space_guarantee'])
- if self.parameters.get('percent_snapshot_space') is not None:
- self.create_volume_attribute(vol_space_attributes, vol_mod_attributes,
- 'percentage-snapshot-reserve', str(self.parameters['percent_snapshot_space']))
- if self.parameters.get('space_slo'):
- self.create_volume_attribute(vol_space_attributes, vol_mod_attributes, 'space-slo', self.parameters['space_slo'])
- # volume-snapshot-attributes
- vol_snapshot_attributes = netapp_utils.zapi.NaElement('volume-snapshot-attributes')
- if self.parameters.get('snapshot_policy'):
- self.create_volume_attribute(vol_snapshot_attributes, vol_mod_attributes,
- 'snapshot-policy', self.parameters['snapshot_policy'])
- if self.parameters.get('snapdir_access'):
- self.create_volume_attribute(vol_snapshot_attributes, vol_mod_attributes,
- 'snapdir-access-enabled', self.parameters['snapdir_access'])
- # volume-export-attributes
- if self.parameters.get('policy'):
- self.create_volume_attribute(vol_mod_attributes, 'volume-export-attributes',
- 'policy', self.parameters['policy'])
- # volume-security-attributes
- if self.parameters.get('unix_permissions'):
- vol_security_attributes = netapp_utils.zapi.NaElement('volume-security-attributes')
- self.create_volume_attribute(vol_security_attributes, 'volume-security-unix-attributes',
- 'permissions', self.parameters['unix_permissions'])
- vol_mod_attributes.add_child_elem(vol_security_attributes)
- # volume-performance-attributes
- if self.parameters.get('atime_update'):
- self.create_volume_attribute(vol_mod_attributes, 'volume-performance-attributes',
- 'is-atime-update-enabled', self.parameters['atime_update'])
- # volume-qos-attributes
- if self.parameters.get('qos_policy_group'):
- self.create_volume_attribute(vol_mod_attributes, 'volume-qos-attributes',
- 'policy-group-name', self.parameters['qos_policy_group'])
- if self.parameters.get('qos_adaptive_policy_group'):
- self.create_volume_attribute(vol_mod_attributes, 'volume-qos-attributes',
- 'adaptive-policy-group-name', self.parameters['qos_adaptive_policy_group'])
- # volume-comp-aggr-attributes
- if params and params.get('tiering_policy'):
- self.create_volume_attribute(vol_mod_attributes, 'volume-comp-aggr-attributes',
- 'tiering-policy', self.parameters['tiering_policy'])
- # volume-state-attributes
- if self.parameters.get('nvfail_enabled') is not None:
- self.create_volume_attribute(vol_mod_attributes, 'volume-state-attributes', 'is-nvfail-enabled', str(self.parameters['nvfail_enabled']))
- # volume-dr-protection-attributes
- if self.parameters.get('vserver_dr_protection') is not None:
- self.create_volume_attribute(vol_mod_attributes, 'volume-vserver-dr-protection-attributes',
- 'vserver-dr-protection', self.parameters['vserver_dr_protection'])
- # volume-id-attributes
- if self.parameters.get('comment') is not None:
- self.create_volume_attribute(vol_mod_attributes, 'volume-id-attributes',
- 'comment', self.parameters['comment'])
- # End of Volume-attributes sub attributes
- attributes.add_child_elem(vol_mod_attributes)
- query = netapp_utils.zapi.NaElement('query')
- vol_query_attributes = netapp_utils.zapi.NaElement('volume-attributes')
- self.create_volume_attribute(vol_query_attributes, 'volume-id-attributes',
- 'name', self.parameters['name'])
- query.add_child_elem(vol_query_attributes)
- vol_mod_iter.add_child_elem(attributes)
- vol_mod_iter.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(vol_mod_iter, enable_tunneling=True)
- failures = result.get_child_by_name('failure-list')
- if self.volume_style == 'flexGroup' or self.parameters['is_infinite']:
- success = result.get_child_by_name('success-list')
- success = success.get_child_by_name('volume-modify-iter-async-info')
- results = dict()
- for key in ('status', 'jobid'):
- if success.get_child_by_name(key):
- results[key] = success[key]
- status = results.get('status')
- if status == 'in_progress' and 'jobid' in results:
- if self.parameters['time_out'] == 0:
- return
- error = self.check_job_status(results['jobid'])
- if error is None:
- return
- else:
- self.module.fail_json(msg='Error when modify volume: %s' % error)
- self.module.fail_json(msg='Unexpected error when modify volume: results is: %s' % repr(results))
- # handle error if modify space, policy, or unix-permissions parameter fails
- if failures is not None:
- if failures.get_child_by_name('volume-modify-iter-info') is not None:
- return_info = 'volume-modify-iter-info'
- error_msg = failures.get_child_by_name(return_info).get_child_content('error-message')
- self.module.fail_json(msg="Error modifying volume %s: %s"
- % (self.parameters['name'], error_msg),
- exception=traceback.format_exc())
- elif failures.get_child_by_name('volume-modify-iter-async-info') is not None:
- return_info = 'volume-modify-iter-async-info'
- error_msg = failures.get_child_by_name(return_info).get_child_content('error-message')
- self.module.fail_json(msg="Error modifying volume %s: %s"
- % (self.parameters['name'], error_msg),
- exception=traceback.format_exc())
- self.ems_log_event("volume-modify")
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error modifying volume %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def volume_mount(self):
- """
- Mount an existing volume in specified junction_path
- :return: None
- """
- vol_mount = netapp_utils.zapi.NaElement('volume-mount')
- vol_mount.add_new_child('volume-name', self.parameters['name'])
- vol_mount.add_new_child('junction-path', self.parameters['junction_path'])
- try:
- self.server.invoke_successfully(vol_mount, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error mounting volume %s on path %s: %s'
- % (self.parameters['name'], self.parameters['junction_path'],
- to_native(error)), exception=traceback.format_exc())
-
- def volume_unmount(self):
- """
- Unmount an existing volume
- :return: None
- """
- vol_unmount = netapp_utils.zapi.NaElement.create_node_with_children(
- 'volume-unmount', **{'volume-name': self.parameters['name']})
- try:
- self.server.invoke_successfully(vol_unmount, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error unmounting volume %s: %s'
- % (self.parameters['name'], to_native(error)), exception=traceback.format_exc())
-
- def modify_volume(self, modify):
- '''Modify volume action'''
- for attribute in modify.keys():
- if attribute == 'size':
- self.resize_volume()
- if attribute == 'is_online':
- self.change_volume_state()
- if attribute == 'aggregate_name':
- self.move_volume()
- if attribute in ['space_guarantee', 'policy', 'unix_permissions', 'tiering_policy',
- 'snapshot_policy', 'percent_snapshot_space', 'snapdir_access', 'atime_update',
- 'nvfail_enabled', 'space_slo', 'qos_policy_group', 'qos_adaptive_policy_group', 'vserver_dr_protection', 'comment']:
- self.volume_modify_attributes(modify)
- if attribute == 'junction_path':
- if modify.get('junction_path') == '':
- self.volume_unmount()
- else:
- self.volume_mount()
-
- def compare_chmod_value(self, current):
- """
- compare current unix_permissions to desire unix_permissions.
- :return: True if the same, False it not the same or desire unix_permissions is not valid.
- """
- desire = self.parameters
- if current is None:
- return False
- octal_value = ''
- unix_permissions = desire['unix_permissions']
- if unix_permissions.isdigit():
- return int(current['unix_permissions']) == int(unix_permissions)
- else:
- if len(unix_permissions) != 12:
- return False
- if unix_permissions[:3] != '---':
- return False
- for i in range(3, len(unix_permissions), 3):
- if unix_permissions[i] not in ['r', '-'] or unix_permissions[i + 1] not in ['w', '-']\
- or unix_permissions[i + 2] not in ['x', '-']:
- return False
- group_permission = self.char_to_octal(unix_permissions[i:i + 3])
- octal_value += str(group_permission)
- return int(current['unix_permissions']) == int(octal_value)
-
- def char_to_octal(self, chars):
- """
- :param chars: Characters to be converted into octal values.
- :return: octal value of the individual group permission.
- """
- total = 0
- if chars[0] == 'r':
- total += 4
- if chars[1] == 'w':
- total += 2
- if chars[2] == 'x':
- total += 1
- return total
-
- def get_volume_style(self, current):
- '''Get volume style, infinite or standard flexvol'''
- if current is None:
- if self.parameters.get('aggr_list') or self.parameters.get('aggr_list_multiplier') or self.parameters.get('auto_provision_as'):
- return 'flexGroup'
- else:
- if current.get('style_extended'):
- if current['style_extended'] == 'flexgroup':
- return 'flexGroup'
- else:
- return current['style_extended']
- return None
-
- def get_job(self, jobid, server):
- """
- Get job details by id
- """
- job_get = netapp_utils.zapi.NaElement('job-get')
- job_get.add_new_child('job-id', jobid)
- try:
- result = server.invoke_successfully(job_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- if to_native(error.code) == "15661":
- # Not found
- return None
- self.module.fail_json(msg='Error fetching job info: %s' % to_native(error),
- exception=traceback.format_exc())
- job_info = result.get_child_by_name('attributes').get_child_by_name('job-info')
- results = {
- 'job-progress': job_info['job-progress'],
- 'job-state': job_info['job-state']
- }
- if job_info.get_child_by_name('job-completion') is not None:
- results['job-completion'] = job_info['job-completion']
- else:
- results['job-completion'] = None
- return results
-
- def check_job_status(self, jobid):
- """
- Loop until job is complete
- """
- server = self.server
- sleep_time = 5
- time_out = self.parameters['time_out']
- results = self.get_job(jobid, server)
- error = 'timeout'
-
- while time_out > 0:
- results = self.get_job(jobid, server)
- # If running as cluster admin, the job is owned by cluster vserver
- # rather than the target vserver.
- if results is None and server == self.server:
- results = netapp_utils.get_cserver(self.server)
- server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- continue
- if results is None:
- error = 'cannot locate job with id: %d' % int(jobid)
- break
- if results['job-state'] in ('queued', 'running'):
- time.sleep(sleep_time)
- time_out -= sleep_time
- continue
- if results['job-state'] in ('success', 'failure'):
- break
- else:
- self.module.fail_json(msg='Unexpected job status in: %s' % repr(results))
-
- if results is not None:
- if results['job-state'] == 'success':
- error = None
- elif results['job-state'] in ('queued', 'running'):
- error = 'job completion exceeded expected timer of: %s seconds' % \
- self.parameters['time_out']
- else:
- if results['job-completion'] is not None:
- error = results['job-completion']
- else:
- error = results['job-progress']
- return error
-
- def check_invoke_result(self, result, action):
- '''
- check invoked api call back result.
- '''
- results = dict()
- for key in ('result-status', 'result-jobid'):
- if result.get_child_by_name(key):
- results[key] = result[key]
- status = results.get('result-status')
- if status == 'in_progress' and 'result-jobid' in results:
- if self.parameters['time_out'] == 0:
- return
- error = self.check_job_status(results['result-jobid'])
- if error is None:
- return
- else:
- self.module.fail_json(msg='Error when %s volume: %s' % (action, error))
- if status == 'failed':
- self.module.fail_json(msg='Operation failed when %s volume.' % action)
-
- def assign_efficiency_policy(self):
- '''Set efficiency policy'''
- options = {'path': '/vol/' + self.parameters['name']}
- efficiency_enable = netapp_utils.zapi.NaElement.create_node_with_children('sis-enable', **options)
- try:
- self.server.invoke_successfully(efficiency_enable, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error enable efficiency on volume %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- options['policy-name'] = self.parameters['efficiency_policy']
- efficiency_start = netapp_utils.zapi.NaElement.create_node_with_children('sis-set-config', **options)
- try:
- self.server.invoke_successfully(efficiency_start, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error setting up an efficiency policy %s on volume %s: %s'
- % (self.parameters['efficiency_policy'], self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
-
- def assign_efficiency_policy_async(self):
- '''Set efficiency policy in asynchronous mode'''
- options = {'volume-name': self.parameters['name']}
- efficiency_enable = netapp_utils.zapi.NaElement.create_node_with_children('sis-enable-async', **options)
- try:
- result = self.server.invoke_successfully(efficiency_enable, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error enable efficiency on volume %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- self.check_invoke_result(result, 'enable efficiency on')
-
- options['policy-name'] = self.parameters['efficiency_policy']
- efficiency_start = netapp_utils.zapi.NaElement.create_node_with_children('sis-set-config-async', **options)
- try:
- result = self.server.invoke_successfully(efficiency_start, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error setting up an efficiency policy on volume %s: %s'
- % (self.parameters['name'], to_native(error)),
- exception=traceback.format_exc())
- self.check_invoke_result(result, 'set efficiency policy on')
-
- def apply(self):
- '''Call create/modify/delete operations'''
- current = self.get_volume()
- self.volume_style = self.get_volume_style(current)
- # rename and create are mutually exclusive
- rename, cd_action, modify = None, None, None
- if self.parameters.get('from_name'):
- rename = self.na_helper.is_rename_action(self.get_volume(self.parameters['from_name']), current)
- else:
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if self.parameters.get('unix_permissions'):
- # current stores unix_permissions' numeric value.
- # unix_permission in self.parameter can be either numeric or character.
- if self.compare_chmod_value(current):
- del self.parameters['unix_permissions']
- if cd_action is None and self.parameters['state'] == 'present':
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if rename:
- self.rename_volume()
- if cd_action == 'create':
- self.create_volume()
- # if we create, and modify only variable are set (snapdir_access or atime_update) we need to run a modify
- if 'snapdir_access' in self.parameters or 'atime_update' in self.parameters:
- self.volume_modify_attributes({'snapdir_access': self.parameters['snapdir_access'],
- 'atime_update': self.parameters['atime_update']})
- elif cd_action == 'delete':
- self.delete_volume()
- elif modify:
- self.modify_volume(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
- def ems_log_event(self, state):
- '''Autosupport log event'''
- if state == 'create':
- message = "A Volume has been created, size: " + \
- str(self.parameters['size']) + str(self.parameters['size_unit'])
- elif state == 'volume-delete':
- message = "A Volume has been deleted"
- elif state == 'volume-move':
- message = "A Volume has been moved"
- elif state == 'volume-rename':
- message = "A Volume has been renamed"
- elif state == 'volume-resize':
- message = "A Volume has been resized to: " + \
- str(self.parameters['size']) + str(self.parameters['size_unit'])
- elif state == 'volume-change':
- message = "A Volume state has been changed"
- else:
- message = "na_ontap_volume has been called"
- netapp_utils.ems_log_event(
- "na_ontap_volume", self.server, event=message)
-
-
-def main():
- '''Apply volume operations from playbook'''
- obj = NetAppOntapVolume()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_volume_autosize.py b/lib/ansible/modules/storage/netapp/na_ontap_volume_autosize.py
deleted file mode 100644
index b0adab1c47..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_volume_autosize.py
+++ /dev/null
@@ -1,361 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2019, NetApp, Inc
-# GNU General Public License v3.0+
-# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
-module: na_ontap_volume_autosize
-short_description: NetApp ONTAP manage volume autosize
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Modify Volume AutoSize
-options:
- volume:
- description:
- - The name of the flexible volume for which we want to set autosize.
- type: str
- required: true
-
- mode:
- description:
- - Specify the flexible volume's autosize mode of operation.
- type: str
- choices: ['grow', 'grow_shrink', 'off']
-
- vserver:
- description:
- - Name of the vserver to use.
- required: true
- type: str
-
- grow_threshold_percent:
- description:
- - Specifies the percentage of the flexible volume's capacity at which autogrow is initiated.
- - The default grow threshold varies from 85% to 98%, depending on the volume size.
- - It is an error for the grow threshold to be less than or equal to the shrink threshold.
- - Range between 0 and 100
- type: int
-
- increment_size:
- description:
- - Specify the flexible volume's increment size using the following format < number > [k|m|g|t]
- - The amount is the absolute size to set.
- - The trailing 'k', 'm', 'g', and 't' indicates the desired units, namely 'kilobytes', 'megabytes', 'gigabytes', and 'terabytes' (respectively).
- type: str
-
- maximum_size:
- description:
- - Specify the flexible volume's maximum allowed size using the following format < number > [k|m|g|t]
- - The amount is the absolute size to set.
- - The trailing 'k', 'm', 'g', and 't' indicates the desired units, namely 'kilobytes', 'megabytes', 'gigabytes', and 'terabytes' (respectively).
- - The default value is 20% greater than the volume size at the time autosize was enabled.
- - It is an error for the maximum volume size to be less than the current volume size.
- - It is also an error for the maximum size to be less than or equal to the minimum size.
- type: str
-
- minimum_size:
- description:
- - Specify the flexible volume's minimum allowed size using the following format < number > [k|m|g|t] The amount is the absolute size to set.
- - The trailing 'k', 'm', 'g', and 't' indicates the desired units, namely 'kilobytes', 'megabytes', 'gigabytes', and 'terabytes' (respectively).
- - The default value is the size of the volume at the time the 'grow_shrink' mode was enabled.
- - It is an error for the minimum size to be greater than or equal to the maximum size.
- type: str
-
- reset:
- description:
- - "Sets the values of maximum_size, increment_size, minimum_size, grow_threshold_percent, shrink_threshold_percent and mode to their defaults"
- type: bool
-
- shrink_threshold_percent:
- description:
- - Specifies the percentage of the flexible volume's capacity at which autoshrink is initiated.
- - The default shrink threshold is 50%. It is an error for the shrink threshold to be greater than or equal to the grow threshold.
- - Range between 0 and 100
- type: int
-'''
-
-EXAMPLES = """
- - name: Modify volume autosize
- na_ontap_volume_autosize:
- hostname: 10.193.79.189
- username: admin
- password: netapp1!
- volume: ansibleVolumesize12
- mode: grow
- grow_threshold_percent: 99
- increment_size: 50m
- maximum_size: 10g
- minimum_size: 21m
- shrink_threshold_percent: 40
- vserver: ansible_vserver
-
- - name: Reset volume autosize
- na_ontap_volume_autosize:
- hostname: 10.193.79.189
- username: admin
- password: netapp1!
- volume: ansibleVolumesize12
- reset: true
- vserver: ansible_vserver
-"""
-
-RETURN = """
-"""
-import sys
-import copy
-import traceback
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.netapp import OntapRestAPI
-from ansible.module_utils._text import to_native
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapVolumeAutosize(object):
- def __init__(self):
- self.use_rest = False
- # Volume_autosize returns KB and not B like Volume so values are shifted down 1
- self._size_unit_map = dict(
- k=1,
- m=1024,
- g=1024 ** 2,
- t=1024 ** 3,
- )
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- volume=dict(required=True, type="str"),
- mode=dict(required=False, choices=['grow', 'grow_shrink', 'off']),
- vserver=dict(required=True, type='str'),
- grow_threshold_percent=dict(required=False, type='int'),
- increment_size=dict(required=False, type='str'),
- maximum_size=dict(required=False, type='str'),
- minimum_size=dict(required=False, type='str'),
- reset=dict(required=False, type='bool'),
- shrink_threshold_percent=dict(required=False, type='int')
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True,
- mutually_exclusive=[
- ['reset', 'maximum_size'],
- ['reset', 'increment_size'],
- ['reset', 'minimum_size'],
- ['reset', 'grow_threshold_percent'],
- ['reset', 'shrink_threshold_percent'],
- ['reset', 'mode']
- ]
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
- # API should be used for ONTAP 9.6 or higher, ZAPI for lower version
- self.restApi = OntapRestAPI(self.module)
- if self.restApi.is_rest():
- self.use_rest = True
- # increment size and reset are not supported with rest api
- if self.parameters.get('increment_size'):
- self.module.fail_json(msg="Rest API does not support increment size, please switch to ZAPI")
- if self.parameters.get('reset'):
- self.module.fail_json(msg="Rest API does not support reset, please switch to ZAPI")
- else:
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_volume_autosize(self, uuid=None):
- """
- Get volume_autosize information from the ONTAP system
- :return:
- """
- if self.use_rest:
- params = {'fields': 'autosize'}
- api = 'storage/volumes/' + uuid
- message, error = self.restApi.get(api, params)
- if error is not None:
- self.module.fail_json(msg="%s" % error)
- return self._create_get_volume_return(message['autosize'])
- else:
- volume_autosize_info = netapp_utils.zapi.NaElement('volume-autosize-get')
- volume_autosize_info.add_new_child('volume', self.parameters['volume'])
- try:
- result = self.server.invoke_successfully(volume_autosize_info, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching volume autosize infor for %s : %s' % (self.parameters['volume'],
- to_native(error)),
- exception=traceback.format_exc())
- return self._create_get_volume_return(result)
-
- def _create_get_volume_return(self, results):
- """
- Create a return value from volume-autosize-get info file
- :param results:
- :return:
- """
- return_value = {}
- if self.use_rest:
- if 'mode' in results:
- return_value['mode'] = results['mode']
- if 'grow_threshold' in results:
- return_value['grow_threshold_percent'] = results['grow_threshold']
- if 'maximum' in results:
- return_value['maximum_size'] = results['maximum']
- if 'minimum' in results:
- return_value['minimum_size'] = results['minimum']
- if 'shrink_threshold' in results:
- return_value['shrink_threshold_percent'] = results['shrink_threshold']
- else:
- if results.get_child_by_name('mode'):
- return_value['mode'] = results.get_child_content('mode')
- if results.get_child_by_name('grow-threshold-percent'):
- return_value['grow_threshold_percent'] = int(results.get_child_content('grow-threshold-percent'))
- if results.get_child_by_name('increment-size'):
- return_value['increment_size'] = results.get_child_content('increment-size')
- if results.get_child_by_name('maximum-size'):
- return_value['maximum_size'] = results.get_child_content('maximum-size')
- if results.get_child_by_name('minimum-size'):
- return_value['minimum_size'] = results.get_child_content('minimum-size')
- if results.get_child_by_name('shrink-threshold-percent'):
- return_value['shrink_threshold_percent'] = int(results.get_child_content('shrink-threshold-percent'))
- if return_value == {}:
- return_value = None
- return return_value
-
- def modify_volume_autosize(self, uuid=None):
- """
- Modify a Volumes autosize
- :return:
- """
- if self.use_rest:
- params = {}
- data = {}
- autosize = {}
- if self.parameters.get('mode'):
- autosize['mode'] = self.parameters['mode']
- if self.parameters.get('grow_threshold_percent'):
- autosize['grow_threshold'] = self.parameters['grow_threshold_percent']
- if self.parameters.get('maximum_size'):
- autosize['maximum'] = self.parameters['maximum_size']
- if self.parameters.get('minimum_size'):
- autosize['minimum'] = self.parameters['minimum_size']
- if self.parameters.get('shrink_threshold_percent'):
- autosize['shrink_threshold'] = self.parameters['shrink_threshold_percent']
- data['autosize'] = autosize
- api = "storage/volumes/" + uuid
- message, error = self.restApi.patch(api, data, params)
- if error is not None:
- self.module.fail_json(msg="%s" % error)
-
- else:
- volume_autosize_info = netapp_utils.zapi.NaElement('volume-autosize-set')
- volume_autosize_info.add_new_child('volume', self.parameters['volume'])
- if self.parameters.get('mode'):
- volume_autosize_info.add_new_child('mode', self.parameters['mode'])
- if self.parameters.get('grow_threshold_percent'):
- volume_autosize_info.add_new_child('grow-threshold-percent', str(self.parameters['grow_threshold_percent']))
- if self.parameters.get('increment_size'):
- volume_autosize_info.add_new_child('increment-size', self.parameters['increment_size'])
- if self.parameters.get('reset') is not None:
- volume_autosize_info.add_new_child('reset', str(self.parameters['reset']))
- if self.parameters.get('maximum_size'):
- volume_autosize_info.add_new_child('maximum-size', self.parameters['maximum_size'])
- if self.parameters.get('minimum_size'):
- volume_autosize_info.add_new_child('minimum-size', self.parameters['minimum_size'])
- if self.parameters.get('shrink_threshold_percent'):
- volume_autosize_info.add_new_child('shrink-threshold-percent', str(self.parameters['shrink_threshold_percent']))
- try:
- self.server.invoke_successfully(volume_autosize_info, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error modify volume autosize for %s: %s" % (self.parameters["volume"], to_native(error)),
- exception=traceback.format_exc())
-
- def modify_to_kb(self, converted_parameters):
- """
- Save a converted parameter
- :param converted_parameters: Dic of all parameters
- :return:
- """
- for attr in ['maximum_size', 'minimum_size', 'increment_size']:
- if converted_parameters.get(attr):
- if self.use_rest:
- converted_parameters[attr] = self.convert_to_byte(attr, converted_parameters)
- else:
- converted_parameters[attr] = str(self.convert_to_kb(attr, converted_parameters))
- return converted_parameters
-
- def convert_to_kb(self, variable, converted_parameters):
- """
- Convert a number 10m in to its correct KB size
- :param variable: the Parameter we are going to covert
- :param converted_parameters: Dic of all parameters
- :return:
- """
- if converted_parameters.get(variable)[-1] not in ['k', 'm', 'g', 't']:
- self.module.fail_json(msg="%s must end with a k, m, g or t" % variable)
- return self._size_unit_map[converted_parameters.get(variable)[-1]] * int(converted_parameters.get(variable)[:-1])
-
- def convert_to_byte(self, variable, converted_parameters):
- if converted_parameters.get(variable)[-1] not in ['k', 'm', 'g', 't']:
- self.module.fail_json(msg="%s must end with a k, m, g or t" % variable)
- return (self._size_unit_map[converted_parameters.get(variable)[-1]] * int(converted_parameters.get(variable)[:-1])) * 1024
-
- def get_volume_uuid(self):
- """
- Get a volume's UUID
- :return: uuid of the volume
- """
- params = {'fields': '*',
- 'name': self.parameters['volume'],
- 'svm.name': self.parameters['vserver']}
- api = "storage/volumes"
- message, error = self.restApi.get(api, params)
- if error is not None:
- self.module.fail_json(msg="%s" % error)
- return message['records'][0]['uuid']
-
- def apply(self):
- # TODO Logging for rest
- uuid = None
- if not self.use_rest:
- netapp_utils.ems_log_event("na_ontap_volume_autosize", self.server)
- if self.use_rest:
- # we only have the volume name, we need to the uuid for the volume
- uuid = self.get_volume_uuid()
- current = self.get_volume_autosize(uuid=uuid)
- converted_parameters = copy.deepcopy(self.parameters)
- converted_parameters = self.modify_to_kb(converted_parameters)
- self.na_helper.get_modified_attributes(current, converted_parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- self.modify_volume_autosize(uuid=uuid)
- if self.parameters.get('reset') is True:
- self.modify_volume_autosize(uuid=uuid)
- self.na_helper.changed = True
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Apply volume autosize operations from playbook
- :return:
- """
- obj = NetAppOntapVolumeAutosize()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_volume_clone.py b/lib/ansible/modules/storage/netapp/na_ontap_volume_clone.py
deleted file mode 100644
index 5fbe4e86d5..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_volume_clone.py
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
-module: na_ontap_volume_clone
-short_description: NetApp ONTAP manage volume clones.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.6'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Create NetApp ONTAP volume clones.
-- A FlexClone License is required to use this module
-options:
- state:
- description:
- - Whether volume clone should be created.
- choices: ['present']
- default: 'present'
- parent_volume:
- description:
- - The parent volume of the volume clone being created.
- required: true
- type: str
- name:
- description:
- - The name of the volume clone being created.
- required: true
- type: str
- aliases:
- - volume
- vserver:
- description:
- - Vserver in which the volume clone should be created.
- required: true
- type: str
- parent_snapshot:
- description:
- - Parent snapshot in which volume clone is created off.
- type: str
- parent_vserver:
- description:
- - Vserver of parent volume in which clone is created off.
- type: str
- qos_policy_group_name:
- description:
- - The qos-policy-group-name which should be set for volume clone.
- type: str
- space_reserve:
- description:
- - The space_reserve setting which should be used for the volume clone.
- choices: ['volume', 'none']
- volume_type:
- description:
- - The volume-type setting which should be used for the volume clone.
- choices: ['rw', 'dp']
- junction_path:
- version_added: '2.8'
- description:
- - Junction path of the volume.
- type: str
- uid:
- version_added: '2.9'
- description:
- - The UNIX user ID for the clone volume.
- type: int
- gid:
- version_added: '2.9'
- description:
- - The UNIX group ID for the clone volume.
- type: int
-'''
-
-EXAMPLES = """
- - name: create volume clone
- na_ontap_volume_clone:
- state: present
- username: "{{ netapp username }}"
- password: "{{ netapp password }}"
- hostname: "{{ netapp hostname }}"
- vserver: vs_hack
- parent_volume: normal_volume
- name: clone_volume_7
- space_reserve: none
- parent_snapshot: backup1
- junction_path: /clone_volume_7
- uid: 1
- gid: 1
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-from ansible.module_utils._text import to_native
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPVolumeClone(object):
- """
- Creates a volume clone
- """
-
- def __init__(self):
- """
- Initialize the NetAppOntapVolumeClone class
- """
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, choices=['present'], default='present'),
- parent_volume=dict(required=True, type='str'),
- name=dict(required=True, type='str', aliases=["volume"]),
- vserver=dict(required=True, type='str'),
- parent_snapshot=dict(required=False, type='str', default=None),
- parent_vserver=dict(required=False, type='str', default=None),
- qos_policy_group_name=dict(required=False, type='str', default=None),
- space_reserve=dict(required=False, choices=['volume', 'none'], default=None),
- volume_type=dict(required=False, choices=['rw', 'dp']),
- junction_path=dict(required=False, type='str', default=None),
- uid=dict(required=False, type='int'),
- gid=dict(required=False, type='int')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True,
- required_together=[
- ['uid', 'gid']
- ]
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
- return
-
- def create_volume_clone(self):
- """
- Creates a new volume clone
- """
- clone_obj = netapp_utils.zapi.NaElement('volume-clone-create')
- clone_obj.add_new_child("parent-volume", self.parameters['parent_volume'])
- clone_obj.add_new_child("volume", self.parameters['volume'])
- if self.parameters.get('qos_policy_group_name'):
- clone_obj.add_new_child("qos-policy-group-name", self.parameters['qos_policy_group_name'])
- if self.parameters.get('space_reserve'):
- clone_obj.add_new_child("space-reserve", self.parameters['space_reserve'])
- if self.parameters.get('parent_snapshot'):
- clone_obj.add_new_child("parent-snapshot", self.parameters['parent_snapshot'])
- if self.parameters.get('parent_vserver'):
- clone_obj.add_new_child("parent-vserver", self.parameters['parent_vserver'])
- if self.parameters.get('volume_type'):
- clone_obj.add_new_child("volume-type", self.parameters['volume_type'])
- if self.parameters.get('junction_path'):
- clone_obj.add_new_child("junction-path", self.parameters['junction_path'])
- if self.parameters.get('uid'):
- clone_obj.add_new_child("uid", str(self.parameters['uid']))
- clone_obj.add_new_child("gid", str(self.parameters['gid']))
- try:
- self.server.invoke_successfully(clone_obj, True)
- except netapp_utils.zapi.NaApiError as exc:
- self.module.fail_json(msg='Error creating volume clone: %s: %s' %
- (self.parameters['volume'], to_native(exc)), exception=traceback.format_exc())
-
- def get_volume_clone(self):
- clone_obj = netapp_utils.zapi.NaElement('volume-clone-get')
- clone_obj.add_new_child("volume", self.parameters['volume'])
- try:
- results = self.server.invoke_successfully(clone_obj, True)
- if results.get_child_by_name('attributes'):
- attributes = results.get_child_by_name('attributes')
- info = attributes.get_child_by_name('volume-clone-info')
- parent_volume = info.get_child_content('parent-volume')
- # checking if clone volume name already used to create by same parent volume
- if parent_volume == self.parameters['parent_volume']:
- return results
- except netapp_utils.zapi.NaApiError as error:
- # Error 15661 denotes an volume clone not being found.
- if to_native(error.code) == "15661":
- pass
- else:
- self.module.fail_json(msg='Error fetching volume clone information %s: %s' %
- (self.parameters['volume'], to_native(error)), exception=traceback.format_exc())
- return None
-
- def apply(self):
- """
- Run Module based on play book
- """
- netapp_utils.ems_log_event("na_ontap_volume_clone", self.server)
- current = self.get_volume_clone()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_volume_clone()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Creates the NetApp Ontap Volume Clone object and runs the correct play task
- """
- obj = NetAppONTAPVolumeClone()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_vscan.py b/lib/ansible/modules/storage/netapp/na_ontap_vscan.py
deleted file mode 100644
index 4eee6329ec..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_vscan.py
+++ /dev/null
@@ -1,178 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_vscan
-short_description: NetApp ONTAP Vscan enable/disable.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-notes:
-- on demand task, on_access_policy and scanner_pools must be set up before running this module
-description:
-- Enable and Disable Vscan
-options:
- enable:
- description:
- - Whether to enable to disable a Vscan
- type: bool
- default: True
-
- vserver:
- description:
- - the name of the data vserver to use.
- required: true
- type: str
-'''
-
-EXAMPLES = """
- - name: Enable Vscan
- na_ontap_vscan:
- enable: True
- username: '{{ netapp_username }}'
- password: '{{ netapp_password }}'
- hostname: '{{ netapp_hostname }}'
- vserver: trident_svm
-
- - name: Disable Vscan
- na_ontap_vscan:
- enable: False
- username: '{{ netapp_username }}'
- password: '{{ netapp_password }}'
- hostname: '{{ netapp_hostname }}'
- vserver: trident_svm
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp import OntapRestAPI
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapVscan(object):
- def __init__(self):
- self.use_rest = False
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- enable=dict(type='bool', default=True),
- vserver=dict(required=True, type='str'),
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- # API should be used for ONTAP 9.6 or higher, Zapi for lower version
- self.restApi = OntapRestAPI(self.module)
- if self.restApi.is_rest():
- self.use_rest = True
- else:
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_vscan(self):
- if self.use_rest:
- params = {'fields': 'svm,enabled',
- "svm.name": self.parameters['vserver']}
- api = "protocols/vscan"
- message, error = self.restApi.get(api, params)
- if error:
- self.module.fail_json(msg=error)
- return message['records'][0]
- else:
- vscan_status_iter = netapp_utils.zapi.NaElement('vscan-status-get-iter')
- vscan_status_info = netapp_utils.zapi.NaElement('vscan-status-info')
- vscan_status_info.add_new_child('vserver', self.parameters['vserver'])
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(vscan_status_info)
- vscan_status_iter.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(vscan_status_iter, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error getting Vscan info for Vserver %s: %s' %
- (self.parameters['vserver'], to_native(error)),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- return result.get_child_by_name('attributes-list').get_child_by_name('vscan-status-info')
-
- def enable_vscan(self, uuid=None):
- if self.use_rest:
- params = {"svm.name": self.parameters['vserver']}
- data = {"enabled": self.parameters['enable']}
- api = "protocols/vscan/" + uuid
- message, error = self.restApi.patch(api, data, params)
- if error is not None:
- self.module.fail_json(msg=error)
- # self.module.fail_json(msg=repr(self.restApi.errors), log=repr(self.restApi.debug_logs))
- else:
- vscan_status_obj = netapp_utils.zapi.NaElement("vscan-status-modify")
- vscan_status_obj.add_new_child('is-vscan-enabled', str(self.parameters['enable']))
- try:
- self.server.invoke_successfully(vscan_status_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg="Error Enable/Disabling Vscan: %s" % to_native(error), exception=traceback.format_exc())
-
- def asup_log(self):
- if self.use_rest:
- # TODO: logging for Rest
- return
- else:
- # Either we are using ZAPI, or REST failed when it should not
- try:
- netapp_utils.ems_log_event("na_ontap_vscan", self.server)
- except Exception:
- # TODO: we may fail to connect to REST or ZAPI, the line below shows REST issues only
- # self.module.fail_json(msg=repr(self.restApi.errors), log=repr(self.restApi.debug_logs))
- pass
-
- def apply(self):
- changed = False
- self.asup_log()
- current = self.get_vscan()
- if self.use_rest:
- if current['enabled'] != self.parameters['enable']:
- if not self.module.check_mode:
- self.enable_vscan(current['svm']['uuid'])
- changed = True
- else:
- if current.get_child_content('is-vscan-enabled') != str(self.parameters['enable']).lower():
- if not self.module.check_mode:
- self.enable_vscan()
- changed = True
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Execute action from playbook
- """
- command = NetAppOntapVscan()
- command.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_vscan_on_access_policy.py b/lib/ansible/modules/storage/netapp/na_ontap_vscan_on_access_policy.py
deleted file mode 100644
index bbe19a6536..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_vscan_on_access_policy.py
+++ /dev/null
@@ -1,366 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_vscan_on_access_policy
-short_description: NetApp ONTAP Vscan on access policy configuration.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Configure on access policy for Vscan (virus scan)
-options:
- state:
- description:
- - Whether a Vscan on Access policy is present or not
- choices: ['present', 'absent']
- default: present
-
- vserver:
- description:
- - the name of the data vserver to use.
- required: true
-
- policy_name:
- description:
- - The name of the policy
- required: true
-
- file_ext_to_exclude:
- description:
- - File extensions for which On-Access scanning must not be performed.
-
- file_ext_to_include:
- description:
- - File extensions for which On-Access scanning is considered. The default value is '*', which means that all files are considered for scanning except
- - those which are excluded from scanning.
-
- filters:
- description:
- - A list of filters which can be used to define the scope of the On-Access policy more precisely. The filters can be added in any order. Possible values
- - scan_ro_volume Enable scans for read-only volume,
- - scan_execute_access Scan only files opened with execute-access (CIFS only)
-
- is_scan_mandatory:
- description:
- - Specifies whether access to a file is allowed if there are no external virus-scanning servers available for virus scanning. It is true if not provided at
- the time of creating a policy.
- type: bool
-
- max_file_size:
- description:
- - Max file-size (in bytes) allowed for scanning. The default value of 2147483648 (2GB) is taken if not provided at the time of creating a policy.
-
- paths_to_exclude:
- description:
- - File paths for which On-Access scanning must not be performed.
-
- scan_files_with_no_ext:
- description:
- - Specifies whether files without any extension are considered for scanning or not.
- default: True
-'''
-
-EXAMPLES = """
- - name: Create Vscan On Access Policy
- na_ontap_vscan_on_access_policy:
- state: present
- username: '{{ netapp_username }}'
- password: '{{ netapp_password }}'
- hostname: '{{ netapp_hostname }}'
- vserver: carchi-vsim2
- policy_name: carchi_policy
- file_ext_to_exclude: ['exe', 'yml']
- - name: modify Vscan on Access Policy
- na_ontap_vscan_on_access_policy:
- state: present
- username: '{{ netapp_username }}'
- password: '{{ netapp_password }}'
- hostname: '{{ netapp_hostname }}'
- vserver: carchi-vsim2
- policy_name: carchi_policy
- file_ext_to_exclude: ['exe', 'yml', 'py']
- - name: Delete On Access Policy
- na_ontap_vscan_on_access_policy:
- state: absent
- username: '{{ netapp_username }}'
- password: '{{ netapp_password }}'
- hostname: '{{ netapp_hostname }}'
- vserver: carchi-vsim2
- policy_name: carchi_policy
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapVscanOnAccessPolicy(object):
- """
- Create/Modify/Delete a Vscan OnAccess policy
- """
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- policy_name=dict(required=True, type='str'),
- file_ext_to_exclude=dict(required=False, type="list"),
- file_ext_to_include=dict(required=False, type="list"),
- filters=dict(required=False, type="list"),
- is_scan_mandatory=dict(required=False, type='bool', default=False),
- max_file_size=dict(required=False, type="int"),
- paths_to_exclude=dict(required=False, type="list"),
- scan_files_with_no_ext=dict(required=False, type=bool, default=True)
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- parameters = self.module.params
- self.state = parameters['state']
- self.vserver = parameters['vserver']
- self.policy_name = parameters['policy_name']
- self.file_ext_to_exclude = parameters['file_ext_to_exclude']
- self.file_ext_to_include = parameters['file_ext_to_include']
- self.filters = parameters['filters']
- self.is_scan_mandatory = parameters['is_scan_mandatory']
- self.max_file_size = parameters['max_file_size']
- self.paths_to_exclude = parameters['paths_to_exclude']
- self.scan_files_with_no_ext = parameters['scan_files_with_no_ext']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver)
-
- def exists_access_policy(self, policy_obj=None):
- """
- Check if a Vscan Access policy exists
- :return: True if Exist, False if it does not
- """
- if policy_obj is None:
- policy_obj = self.return_on_access_policy()
- if policy_obj:
- return True
- else:
- return False
-
- def return_on_access_policy(self):
- """
- Return a Vscan on Access Policy
- :return: None if there is no access policy, return the policy if there is
- """
- access_policy_obj = netapp_utils.zapi.NaElement('vscan-on-access-policy-get-iter')
- access_policy_info = netapp_utils.zapi.NaElement('vscan-on-access-policy-info')
- access_policy_info.add_new_child('policy-name', self.policy_name)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(access_policy_info)
- access_policy_obj.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(access_policy_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error searching Vscan on Access Policy %s: %s' %
- (self.policy_name, to_native(error)), exception=traceback.format_exc())
- if result.get_child_by_name('num-records'):
- if int(result.get_child_content('num-records')) == 1:
- return result
- elif int(result.get_child_content('num-records')) > 1:
- self.module.fail_json(msg='Multiple Vscan on Access Policy matching %s:' % self.policy_name)
- return None
-
- def create_on_access_policy(self):
- """
- Create a Vscan on Access policy
- :return: none
- """
- access_policy_obj = netapp_utils.zapi.NaElement('vscan-on-access-policy-create')
- access_policy_obj.add_new_child('policy-name', self.policy_name)
- access_policy_obj.add_new_child('protocol', 'cifs')
- access_policy_obj = self._fill_in_access_policy(access_policy_obj)
-
- try:
- self.server.invoke_successfully(access_policy_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating Vscan on Access Policy %s: %s' %
- (self.policy_name, to_native(error)), exception=traceback.format_exc())
-
- def delete_on_access_policy(self):
- """
- Delete a Vscan On Access Policy
- :return:
- """
- access_policy_obj = netapp_utils.zapi.NaElement('vscan-on-access-policy-delete')
- access_policy_obj.add_new_child('policy-name', self.policy_name)
- try:
- self.server.invoke_successfully(access_policy_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error Deleting Vscan on Access Policy %s: %s' %
- (self.policy_name, to_native(error)), exception=traceback.format_exc())
-
- def modify_on_access_policy(self):
- """
- Modify a Vscan On Access policy
- :return: nothing
- """
- access_policy_obj = netapp_utils.zapi.NaElement('vscan-on-access-policy-modify')
- access_policy_obj.add_new_child('policy-name', self.policy_name)
- access_policy_obj = self._fill_in_access_policy(access_policy_obj)
- try:
- self.server.invoke_successfully(access_policy_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error Modifying Vscan on Access Policy %s: %s' %
- (self.policy_name, to_native(error)), exception=traceback.format_exc())
-
- def _fill_in_access_policy(self, access_policy_obj):
- if self.is_scan_mandatory is not None:
- access_policy_obj.add_new_child('is-scan-mandatory', str(self.is_scan_mandatory).lower())
- if self.max_file_size:
- access_policy_obj.add_new_child('max-file-size', str(self.max_file_size))
- if self.scan_files_with_no_ext is not None:
- access_policy_obj.add_new_child('scan-files-with-no-ext', str(self.scan_files_with_no_ext))
- if self.file_ext_to_exclude:
- ext_obj = netapp_utils.zapi.NaElement('file-ext-to-exclude')
- access_policy_obj.add_child_elem(ext_obj)
- for extension in self.file_ext_to_exclude:
- ext_obj.add_new_child('file-extension', extension)
- if self.file_ext_to_include:
- ext_obj = netapp_utils.zapi.NaElement('file-ext-to-include')
- access_policy_obj.add_child_elem(ext_obj)
- for extension in self.file_ext_to_include:
- ext_obj.add_new_child('file-extension', extension)
- if self.filters:
- ui_filter_obj = netapp_utils.zapi.NaElement('filters')
- access_policy_obj.add_child_elem(ui_filter_obj)
- for filter in self.filters:
- ui_filter_obj.add_new_child('vscan-on-access-policy-ui-filter', filter)
- if self.paths_to_exclude:
- path_obj = netapp_utils.zapi.NaElement('paths-to-exclude')
- access_policy_obj.add_child_elem(path_obj)
- for path in self.paths_to_exclude:
- path_obj.add_new_child('file-path', path)
- return access_policy_obj
-
- def has_policy_changed(self):
- results = self.return_on_access_policy()
- if results is None:
- return False
- try:
- policy_obj = results.get_child_by_name('attributes-list').get_child_by_name('vscan-on-access-policy-info')
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error Accessing on access policy %s: %s' %
- (self.policy_name, to_native(error)), exception=traceback.format_exc())
- if self.is_scan_mandatory is not None:
- if str(self.is_scan_mandatory).lower() != policy_obj.get_child_content('is-scan-mandatory'):
- return True
- if self.max_file_size:
- if self.max_file_size != int(policy_obj.get_child_content('max-file-size')):
- return True
- if self.scan_files_with_no_ext is not None:
- if str(self.scan_files_with_no_ext).lower() != policy_obj.get_child_content('scan-files-with-no-ext'):
- return True
- if self.file_ext_to_exclude:
- # if no file-ext-to-exclude are given at creation, XML will not have a file-ext-to-exclude
- if policy_obj.get_child_by_name('file-ext-to-exclude') is None:
- return True
- current_to_exclude = []
- for each in policy_obj.get_child_by_name('file-ext-to-exclude').get_children():
- current_to_exclude.append(each.get_content())
- k = self._diff(self.file_ext_to_exclude, current_to_exclude)
- # If the diff returns something the lists don't match and the policy has changed
- if k:
- return True
- if self.file_ext_to_include:
- # if no file-ext-to-include are given at creation, XML will not have a file-ext-to-include
- if policy_obj.get_child_by_name('file-ext-to-include') is None:
- return True
- current_to_include = []
- for each in policy_obj.get_child_by_name('file-ext-to-include').get_children():
- current_to_include.append(each.get_content())
- k = self._diff(self.file_ext_to_include, current_to_include)
- # If the diff returns something the lists don't match and the policy has changed
- if k:
- return True
- if self.filters:
- if policy_obj.get_child_by_name('filters') is None:
- return True
- current_filters = []
- for each in policy_obj.get_child_by_name('filters').get_children():
- current_filters.append(each.get_content())
- k = self._diff(self.filters, current_filters)
- # If the diff returns something the lists don't match and the policy has changed
- if k:
- return True
- if self.paths_to_exclude:
- if policy_obj.get_child_by_name('paths-to-exclude') is None:
- return True
- current_paths_to_exlude = []
- for each in policy_obj.get_child_by_name('paths-to-exclude').get_children():
- current_paths_to_exlude.append(each.get_content())
- k = self._diff(self.paths_to_exclude, current_paths_to_exlude)
- # If the diff returns something the lists don't match and the policy has changed
- if k:
- return True
- return False
-
- def _diff(self, li1, li2):
- """
- :param li1: list 1
- :param li2: list 2
- :return: a list contain items that are not on both lists
- """
- li_dif = [i for i in li1 + li2 if i not in li1 or i not in li2]
- return li_dif
-
- def apply(self):
- netapp_utils.ems_log_event("na_ontap_vscan_on_access_policy", self.server)
- changed = False
- policy_obj = self.return_on_access_policy()
- if self.state == 'present':
- if not self.exists_access_policy(policy_obj):
- if not self.module.check_mode:
- self.create_on_access_policy()
- changed = True
- else:
- # Check if anything has changed first.
- if self.has_policy_changed():
- if not self.module.check_mode:
- self.modify_on_access_policy()
- changed = True
- if self.state == 'absent':
- if self.exists_access_policy(policy_obj):
- if not self.module.check_mode:
- self.delete_on_access_policy()
- changed = True
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Execute action from playbook
- """
- command = NetAppOntapVscanOnAccessPolicy()
- command.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_vscan_on_demand_task.py b/lib/ansible/modules/storage/netapp/na_ontap_vscan_on_demand_task.py
deleted file mode 100644
index 63b65a211c..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_vscan_on_demand_task.py
+++ /dev/null
@@ -1,313 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
-module: na_ontap_vscan_on_demand_task
-short_description: NetApp ONTAP Vscan on demand task configuration.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Configure on demand task for Vscan
-options:
- state:
- description:
- - Whether a Vscan on demand task is present or not
- choices: ['present', 'absent']
- default: present
-
- vserver:
- description:
- - the name of the data vserver to use.
- required: true
-
- cross_junction:
- description:
- - Specifies whether the On-Demand task is allowed to cross volume junctions
- type: bool
- default: False
-
- directory_recursion:
- description:
- - Specifies whether the On-Demand task is allowed to recursively scan through sub-directories.
- type: bool
- default: False
-
- file_ext_to_exclude:
- description:
- - File-Extensions for which scanning must not be performed.
- - File whose extension matches with both inclusion and exclusion list is not considered for scanning.
- type: list
-
- file_ext_to_include:
- description:
- - File extensions for which scanning is considered.
- - The default value is '*', which means that all files are considered for scanning except those which are excluded from scanning.
- - File whose extension matches with both inclusion and exclusion list is not considered for scanning.
- type: list
-
- max_file_size:
- description:
- - Max file-size (in bytes) allowed for scanning. The default value of 10737418240 (10GB) is taken if not provided at the time of creating a task.
-
- paths_to_exclude:
- description:
- - File-paths for which scanning must not be performed.
- type: list
-
- report_directory:
- description:
- - Path from the vserver root where task report is created. The path must be a directory and provided in unix-format from the root of the Vserver.
- - Example /vol1/on-demand-reports.
-
- report_log_level:
- description:
- - Log level for the On-Demand report.
- choices: ['verbose', 'info', 'error']
- default: error
-
- request_timeout:
- description:
- - Total request-service time-limit in seconds. If the virus-scanner does not respond within the provided time, scan will be timed out.
-
- scan_files_with_no_ext:
- description:
- - Specifies whether files without any extension are considered for scanning or not.
- type: bool
- default: True
-
- scan_paths:
- description:
- - List of paths that need to be scanned. The path must be provided in unix-format and from the root of the Vserver.
- - Example /vol1/large_files.
- type: list
-
- scan_priority:
- description:
- - Priority of the On-Demand scan requests generated by this task.
- choices: ['low', 'normal']
- default: low
-
- schedule:
- description:
- - Schedule of the task. The task will be run as per the schedule.
- - For running the task immediately, vscan-on-demand-task-run api must be used after creating a task.
-
- task_name:
- description:
- - Name of the task.
- required: True
-'''
-
-
-EXAMPLES = """
- - name: Create Vscan On Demand Task
- na_ontap_vscan_on_demand_task:
- state: present
- username: '{{ netapp_username }}'
- password: '{{ netapp_password }}'
- hostname: '{{ netapp_hostname }}'
- vserver: carchi-vsim2
- task_name: carchiOnDemand
- scan_paths: /
- report_directory: /
- file_ext_to_exclude: ['py', 'yml']
- max_file_size: 10737418241
- paths_to_exclude: ['/tmp', '/var']
- report_log_level: info
- request_timeout: 60
-
- - name: Delete Vscan On Demand Task
- na_ontap_vscan_on_demand_task:
- state: absent
- username: '{{ netapp_username }}'
- password: '{{ netapp_password }}'
- hostname: '{{ netapp_hostname }}'
- vserver: carchi-vsim2
- task_name: carchiOnDemand
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapVscanOnDemandTask(object):
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- cross_junction=dict(required=False, type='bool', default=False),
- directory_recursion=dict(required=False, type='bool', default=False),
- file_ext_to_exclude=dict(required=False, type="list"),
- file_ext_to_include=dict(required=False, type="list"),
- max_file_size=dict(required=False, type="str"),
- paths_to_exclude=dict(required=False, type="list"),
- report_directory=dict(required=False, type='str'),
- report_log_level=dict(required=False, choices=['verbose', 'info', 'error'], default='error'),
- request_timeout=dict(required=False, type='str'),
- scan_files_with_no_ext=dict(required=False, type='bool', default=True),
- scan_paths=dict(required=False, type="list"),
- scan_priority=dict(required=False, choices=['low', 'normal'], default='low'),
- schedule=dict(required=False, type="str"),
- task_name=dict(required=True, type="str")
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True,
- required_if=[
- ["state", "present", ["report_directory", "scan_paths"]]
- ]
- )
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def get_demand_task(self):
- """
- Get a demand task
- :return: A vscan-on-demand-task-info or None
- """
- demand_task_iter = netapp_utils.zapi.NaElement("vscan-on-demand-task-get-iter")
- demand_task_info = netapp_utils.zapi.NaElement("vscan-on-demand-task-info")
- demand_task_info.add_new_child('task-name', self.parameters['task_name'])
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(demand_task_info)
- demand_task_iter.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(demand_task_iter, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error searching for Vscan on demand task %s: %s' %
- (self.parameters['task_name'], to_native(error)),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- return result.get_child_by_name('attributes-list').get_child_by_name('vscan-on-demand-task-info')
- return None
-
- def create_demand_task(self):
- """
- Create a Demand Task
- :return: None
- """
- demand_task_obj = netapp_utils.zapi.NaElement("vscan-on-demand-task-create")
- # Required items first
- demand_task_obj.add_new_child('report-directory', self.parameters['report_directory'])
- demand_task_obj.add_new_child('task-name', self.parameters['task_name'])
- scan_paths = netapp_utils.zapi.NaElement("scan-paths")
- for scan_path in self.parameters['scan_paths']:
- scan_paths.add_new_child('string', scan_path)
- demand_task_obj.add_child_elem(scan_paths)
- # Optional items next
- if self.parameters.get('cross_junction'):
- demand_task_obj.add_new_child('cross-junction', str(self.parameters['cross_junction']).lower())
- if self.parameters.get('directory_recursion'):
- demand_task_obj.add_new_child('directory-recursion', str(self.parameters['directory_recursion']).lower())
- if self.parameters.get('file_ext_to_exclude'):
- ext_to_exclude_obj = netapp_utils.zapi.NaElement('file-ext-to-exclude')
- for exclude_file in self.parameters['file_ext_to_exclude']:
- ext_to_exclude_obj.add_new_child('file-extension', exclude_file)
- demand_task_obj.add_child_elem(ext_to_exclude_obj)
- if self.parameters.get('file_ext_to_include'):
- ext_to_include_obj = netapp_utils.zapi.NaElement('file-ext-to-include')
- for include_file in self.parameters['file_ext_to_exclude']:
- ext_to_include_obj.add_child_elem('file-extension', include_file)
- demand_task_obj.add_child_elem(ext_to_include_obj)
- if self.parameters.get('max_file_size'):
- demand_task_obj.add_new_child('max-file-size', self.parameters['max_file_size'])
- if self.parameters.get('paths_to_exclude'):
- exclude_paths = netapp_utils.zapi.NaElement('paths-to-exclude')
- for path in self.parameters['paths_to_exclude']:
- exclude_paths.add_new_child('string', path)
- demand_task_obj.add_child_elem(exclude_paths)
- if self.parameters.get('report_log_level'):
- demand_task_obj.add_new_child('report-log-level', self.parameters['report_log_level'])
- if self.parameters.get('request_timeout'):
- demand_task_obj.add_new_child('request-timeout', self.parameters['request_timeout'])
- if self.parameters.get('scan_files_with_no_ext'):
- demand_task_obj.add_new_child('scan-files-with-no-ext', str(self.parameters['scan_files_with_no_ext']).lower())
- if self.parameters.get('scan_priority'):
- demand_task_obj.add_new_child('scan-priority', self.parameters['scan_priority'].lower())
- if self.parameters.get('schedule'):
- demand_task_obj.add_new_child('schedule', self.parameters['schedule'])
- try:
- result = self.server.invoke_successfully(demand_task_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating on demand task %s: %s' %
- (self.parameters['task_name'], to_native(error)),
- exception=traceback.format_exc())
-
- def delete_demand_task(self):
- """
- Delete a Demand Task"
- :return:
- """
- demand_task_obj = netapp_utils.zapi.NaElement('vscan-on-demand-task-delete')
- demand_task_obj.add_new_child('task-name', self.parameters['task_name'])
- try:
- self.server.invoke_successfully(demand_task_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting on demand task, %s: %s' %
- (self.parameters['task_name'], to_native(error)),
- exception=traceback.format_exc())
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
- def apply(self):
- self.asup_log_for_cserver("na_ontap_vscan_on_demand_task")
- current = self.get_demand_task()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if cd_action == 'create':
- self.create_demand_task()
- elif cd_action == 'delete':
- self.delete_demand_task()
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """
- Execute action from playbook
- """
- command = NetAppOntapVscanOnDemandTask()
- command.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_vscan_scanner_pool.py b/lib/ansible/modules/storage/netapp/na_ontap_vscan_scanner_pool.py
deleted file mode 100644
index b5e14f62df..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_vscan_scanner_pool.py
+++ /dev/null
@@ -1,240 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
-module: na_ontap_vscan_scanner_pool
-short_description: NetApp ONTAP Vscan Scanner Pools Configuration.
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.8'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
-- Configure a Vscan Scanner Pool
-options:
- state:
- description:
- - Whether a Vscan Scanner pool is present or not
- choices: ['present', 'absent']
- default: present
-
- vserver:
- description:
- - the name of the data vserver to use.
- required: true
-
- hostnames:
- description:
- - List of hostnames of Vscan servers which are allowed to connect to Data ONTAP
-
- privileged_users:
- description:
- - List of privileged usernames. Username must be in the form "domain-name\\user-name"
-
- scanner_pool:
- description:
- - the name of the virus scanner pool
- required: true
-
- scanner_policy:
- description:
- - The name of the Virus scanner Policy
- choices: ['primary', 'secondary', 'idle']
-'''
-
-EXAMPLES = """
-- name: Create and enable Scanner pool
- na_ontap_vscan_scanner_pool:
- state: present
- username: '{{ netapp_username }}'
- password: '{{ netapp_password }}'
- hostname: '{{ netapp_hostname }}'
- vserver: carchi-vsim2
- hostnames: ['name', 'name2']
- privileged_users: ['sim.rtp.openeng.netapp.com\\admin', 'sim.rtp.openeng.netapp.com\\carchi']
- scanner_pool: Scanner1
- scanner_policy: primary
-
-- name: Delete a scanner pool
- na_ontap_vscan_scanner_pool:
- state: absent
- username: '{{ netapp_username }}'
- password: '{{ netapp_password }}'
- hostname: '{{ netapp_hostname }}'
- vserver: carchi-vsim2
- scanner_pool: Scanner1
-"""
-
-RETURN = """
-
-"""
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppOntapVscanScannerPool(object):
-
- def __init__(self):
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- hostnames=dict(required=False, type='list'),
- privileged_users=dict(required=False, type='list'),
- scanner_pool=dict(required=True, type='str'),
- scanner_policy=dict(required=False, choices=['primary', 'secondary', 'idle'])
- ))
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
- parameters = self.module.params
- self.hostnames = parameters['hostnames']
- self.vserver = parameters['vserver']
- self.privileged_users = parameters['privileged_users']
- self.scanner_pool = parameters['scanner_pool']
- self.state = parameters['state']
- self.scanner_policy = parameters['scanner_policy']
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver)
-
- def create_scanner_pool(self):
- """
- Create a Vscan Scanner Pool
- :return: nothing
- """
- scanner_pool_obj = netapp_utils.zapi.NaElement('vscan-scanner-pool-create')
- if self.hostnames:
- string_obj = netapp_utils.zapi.NaElement('hostnames')
- scanner_pool_obj.add_child_elem(string_obj)
- for hostname in self.hostnames:
- string_obj.add_new_child('string', hostname)
- if self.privileged_users:
- users_obj = netapp_utils.zapi.NaElement('privileged-users')
- scanner_pool_obj.add_child_elem(users_obj)
- for user in self.privileged_users:
- users_obj.add_new_child('privileged-user', user)
- scanner_pool_obj.add_new_child('scanner-pool', self.scanner_pool)
- try:
- self.server.invoke_successfully(scanner_pool_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating Vscan Scanner Pool %s: %s' %
- (self.scanner_pool, to_native(error)),
- exception=traceback.format_exc())
-
- def apply_policy(self):
- """
- Apply a Scanner policy to a Scanner pool
- :return: nothing
- """
- apply_policy_obj = netapp_utils.zapi.NaElement('vscan-scanner-pool-apply-policy')
- apply_policy_obj.add_new_child('scanner-policy', self.scanner_policy)
- apply_policy_obj.add_new_child('scanner-pool', self.scanner_pool)
- try:
- self.server.invoke_successfully(apply_policy_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error applying policy %s to pool %s: %s' %
- (self.scanner_policy, self.scanner_pool, to_native(error)),
- exception=traceback.format_exc())
-
- def get_scanner_pool(self):
- """
- Check to see if a scanner pool exist or not
- :return: True if it exist, False if it does not
- """
- scanner_pool_obj = netapp_utils.zapi.NaElement('vscan-scanner-pool-get-iter')
- scanner_pool_info = netapp_utils.zapi.NaElement('scan-scanner-pool-info')
- scanner_pool_info.add_new_child('scanner-pool', self.scanner_pool)
- scanner_pool_info.add_new_child('vserver', self.vserver)
- query = netapp_utils.zapi.NaElement('query')
- query.add_child_elem(scanner_pool_info)
- scanner_pool_obj.add_child_elem(query)
- try:
- result = self.server.invoke_successfully(scanner_pool_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error searching for Vscan Scanner Pool %s: %s' %
- (self.scanner_pool, to_native(error)),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
- if result.get_child_by_name('attributes-list').get_child_by_name('vscan-scanner-pool-info').get_child_content(
- 'scanner-pool') == self.scanner_pool:
- return result.get_child_by_name('attributes-list').get_child_by_name('vscan-scanner-pool-info')
- return False
- return False
-
- def delete_scanner_pool(self):
- """
- Delete a Scanner pool
- :return: nothing
- """
- scanner_pool_obj = netapp_utils.zapi.NaElement('vscan-scanner-pool-delete')
- scanner_pool_obj.add_new_child('scanner-pool', self.scanner_pool)
- try:
- self.server.invoke_successfully(scanner_pool_obj, True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting Vscan Scanner Pool %s: %s' %
- (self.scanner_pool, to_native(error)),
- exception=traceback.format_exc())
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
- def apply(self):
- self.asup_log_for_cserver("na_ontap_vscan_scanner_pool")
- changed = False
- scanner_pool_obj = self.get_scanner_pool()
- if self.state == 'present':
- if not scanner_pool_obj:
- self.create_scanner_pool()
- if self.scanner_policy:
- self.apply_policy()
- changed = True
- # apply Scanner policy
- if scanner_pool_obj:
- if self.scanner_policy:
- if scanner_pool_obj.get_child_content('scanner-policy') != self.scanner_policy:
- self.apply_policy()
- changed = True
- if self.state == 'absent':
- if scanner_pool_obj:
- self.delete_scanner_pool()
- changed = True
- self.module.exit_json(changed=changed)
-
-
-def main():
- """
- Execute action from playbook
- """
- command = NetAppOntapVscanScannerPool()
- command.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_vserver_cifs_security.py b/lib/ansible/modules/storage/netapp/na_ontap_vserver_cifs_security.py
deleted file mode 100644
index afb66d2ee2..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_vserver_cifs_security.py
+++ /dev/null
@@ -1,282 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
----
-module: na_ontap_vserver_cifs_security
-short_description: NetApp ONTAP vserver CIFS security modification
-extends_documentation_fragment:
- - netapp.na_ontap
-version_added: '2.9'
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-
-description:
- - modify vserver CIFS security.
-
-options:
-
- vserver:
- description:
- - name of the vserver.
- required: true
- type: str
-
- kerberos_clock_skew:
- description:
- - The clock skew in minutes is the tolerance for accepting tickets with time stamps that do not exactly match the host's system clock.
- type: int
-
- kerberos_ticket_age:
- description:
- - Determine the maximum amount of time in hours that a user's ticket may be used for the purpose of Kerberos authentication.
- type: int
-
- kerberos_renew_age:
- description:
- - Determine the maximum amount of time in days for which a ticket can be renewed.
- type: int
-
- kerberos_kdc_timeout:
- description:
- - Determine the timeout value in seconds for KDC connections.
- type: int
-
- is_signing_required:
- description:
- - Determine whether signing is required for incoming CIFS traffic.
- type: bool
-
- is_password_complexity_required:
- description:
- - Determine whether password complexity is required for local users.
- type: bool
-
- is_aes_encryption_enabled:
- description:
- - Determine whether AES-128 and AES-256 encryption mechanisms are enabled for Kerberos-related CIFS communication.
- type: bool
-
- is_smb_encryption_required:
- description:
- - Determine whether SMB encryption is required for incoming CIFS traffic.
- type: bool
-
- lm_compatibility_level:
- description:
- - Determine the LM compatibility level.
- choices: ['lm_ntlm_ntlmv2_krb', 'ntlm_ntlmv2_krb', 'ntlmv2_krb', 'krb']
- type: str
-
- referral_enabled_for_ad_ldap:
- description:
- - Determine whether LDAP referral chasing is enabled or not for AD LDAP connections.
- type: bool
-
- session_security_for_ad_ldap:
- description:
- - Determine the level of security required for LDAP communications.
- choices: ['none', 'sign', 'seal']
- type: str
-
- smb1_enabled_for_dc_connections:
- description:
- - Determine if SMB version 1 is used for connections to domain controllers.
- choices: ['false', 'true', 'system_default']
- type: str
-
- smb2_enabled_for_dc_connections:
- description:
- - Determine if SMB version 2 is used for connections to domain controllers.
- choices: ['false', 'true', 'system_default']
- type: str
-
- use_start_tls_for_ad_ldap:
- description:
- - Determine whether to use start_tls for AD LDAP connections.
- type: bool
-
-'''
-
-EXAMPLES = '''
- - name: modify cifs security
- na_ontap_vserver_cifs_security:
- vserver: ansible
- hostname: "{{ hostname }}"
- kerberos_clock_skew: 5
- kerberos_ticket_age: 5
- kerberos_renew_age: 10
- kerberos_kdc_timeout: 5
- is_signing_required: true
- is_password_complexity_required: true
- is_aes_encryption_enabled: true
- is_smb_encryption_required: true
- lm_compatibility_level: krb
- smb1_enabled_for_dc_connections: true
- smb2_enabled_for_dc_connections: true
- use_start_tls_for_ad_ldap: true
- username: username
- password: password
-
- - name: modify cifs security
- na_ontap_vserver_cifs_security:
- vserver: ansible
- hostname: "{{ hostname }}"
- referral_enabled_for_ad_ldap: true
- username: username
- password: password
-
- - name: modify cifs security
- na_ontap_vserver_cifs_security:
- vserver: ansible
- hostname: "{{ hostname }}"
- session_security_for_ad_ldap: true
- username: username
- password: password
-'''
-
-RETURN = '''
-'''
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPCifsSecurity(object):
- '''
- modify vserver cifs security
- '''
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- vserver=dict(required=True, type='str'),
- kerberos_clock_skew=dict(required=False, type='int'),
- kerberos_ticket_age=dict(required=False, type='int'),
- kerberos_renew_age=dict(required=False, type='int'),
- kerberos_kdc_timeout=dict(required=False, type='int'),
- is_signing_required=dict(required=False, type='bool'),
- is_password_complexity_required=dict(required=False, type='bool'),
- is_aes_encryption_enabled=dict(required=False, type='bool'),
- is_smb_encryption_required=dict(required=False, type='bool'),
- lm_compatibility_level=dict(required=False, choices=['lm_ntlm_ntlmv2_krb', 'ntlm_ntlmv2_krb', 'ntlmv2_krb', 'krb']),
- referral_enabled_for_ad_ldap=dict(required=False, type='bool'),
- session_security_for_ad_ldap=dict(required=False, choices=['none', 'sign', 'seal']),
- smb1_enabled_for_dc_connections=dict(required=False, choices=['false', 'true', 'system_default']),
- smb2_enabled_for_dc_connections=dict(required=False, choices=['false', 'true', 'system_default']),
- use_start_tls_for_ad_ldap=dict(required=False, type='bool')
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
-
- def cifs_security_get_iter(self):
- """
- get current vserver cifs security.
- :return: a dict of vserver cifs security
- """
- cifs_security_get = netapp_utils.zapi.NaElement('cifs-security-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- cifs_security = netapp_utils.zapi.NaElement('cifs-security')
- cifs_security.add_new_child('vserver', self.parameters['vserver'])
- query.add_child_elem(cifs_security)
- cifs_security_get.add_child_elem(query)
- cifs_security_details = dict()
- try:
- result = self.server.invoke_successfully(cifs_security_get, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching cifs security from %s: %s'
- % (self.parameters['vserver'], to_native(error)),
- exception=traceback.format_exc())
- if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) > 0:
- cifs_security_info = result.get_child_by_name('attributes-list').get_child_by_name('cifs-security')
- cifs_security_details['kerberos_clock_skew'] = cifs_security_info.get_child_content('kerberos-clock-skew')
- cifs_security_details['kerberos_ticket_age'] = cifs_security_info.get_child_content('kerberos-ticket-age')
- cifs_security_details['kerberos_renew_age'] = cifs_security_info.get_child_content('kerberos-renew-age')
- cifs_security_details['kerberos_kdc_timeout'] = cifs_security_info.get_child_content('kerberos-kdc-timeout')
- cifs_security_details['is_signing_required'] = bool(cifs_security_info.get_child_content('is-signing-required'))
- cifs_security_details['is_password_complexity_required'] = bool(cifs_security_info.get_child_content('is-password-complexity-required'))
- cifs_security_details['is_aes_encryption_enabled'] = bool(cifs_security_info.get_child_content('is-aes-encryption-enabled'))
- cifs_security_details['is_smb_encryption_required'] = bool(cifs_security_info.get_child_content('is-smb-encryption-required'))
- cifs_security_details['lm_compatibility_level'] = cifs_security_info.get_child_content('lm-compatibility-level')
- cifs_security_details['referral_enabled_for_ad_ldap'] = bool(cifs_security_info.get_child_content('referral-enabled-for-ad-ldap'))
- cifs_security_details['session_security_for_ad_ldap'] = cifs_security_info.get_child_content('session-security-for-ad-ldap')
- cifs_security_details['smb1_enabled_for_dc_connections'] = cifs_security_info.get_child_content('smb1-enabled-for-dc-connections')
- cifs_security_details['smb2_enabled_for_dc_connections'] = cifs_security_info.get_child_content('smb2-enabled-for-dc-connections')
- cifs_security_details['use_start_tls_for_ad_ldap'] = bool(cifs_security_info.get_child_content('use-start-tls-for-ad-ldap'))
- return cifs_security_details
- return None
-
- def cifs_security_modify(self, modify):
- """
- :param modify: A list of attributes to modify
- :return: None
- """
- cifs_security_modify = netapp_utils.zapi.NaElement('cifs-security-modify')
- for attribute in modify:
- cifs_security_modify.add_new_child(self.attribute_to_name(attribute), str(self.parameters[attribute]))
- try:
- self.server.invoke_successfully(cifs_security_modify, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as e:
- self.module.fail_json(msg='Error modifying cifs security on %s: %s'
- % (self.parameters['vserver'], to_native(e)),
- exception=traceback.format_exc())
-
- @staticmethod
- def attribute_to_name(attribute):
- return str.replace(attribute, '_', '-')
-
- def apply(self):
- """Call modify operations."""
- self.asup_log_for_cserver("na_ontap_vserver_cifs_security")
- current = self.cifs_security_get_iter()
- modify = self.na_helper.get_modified_attributes(current, self.parameters)
- if self.na_helper.changed:
- if self.module.check_mode:
- pass
- else:
- if modify:
- self.cifs_security_modify(modify)
- self.module.exit_json(changed=self.na_helper.changed)
-
- def asup_log_for_cserver(self, event_name):
- """
- Fetch admin vserver for the given cluster
- Create and Autosupport log event with the given module name
- :param event_name: Name of the event log
- :return: None
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event(event_name, cserver)
-
-
-def main():
- obj = NetAppONTAPCifsSecurity()
- obj.apply()
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_vserver_peer.py b/lib/ansible/modules/storage/netapp/na_ontap_vserver_peer.py
deleted file mode 100644
index c0c9db3e4a..0000000000
--- a/lib/ansible/modules/storage/netapp/na_ontap_vserver_peer.py
+++ /dev/null
@@ -1,276 +0,0 @@
-#!/usr/bin/python
-
-# (c) 2018-2019, NetApp, Inc
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = '''
-author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com>
-description:
- - Create/Delete vserver peer
-extends_documentation_fragment:
- - netapp.na_ontap
-module: na_ontap_vserver_peer
-options:
- state:
- choices: ['present', 'absent']
- description:
- - Whether the specified vserver peer should exist or not.
- default: present
- vserver:
- description:
- - Specifies name of the source Vserver in the relationship.
- applications:
- choices: ['snapmirror', 'file_copy', 'lun_copy', 'flexcache']
- description:
- - List of applications which can make use of the peering relationship.
- - FlexCache supported from ONTAP 9.5 onwards.
- peer_vserver:
- description:
- - Specifies name of the peer Vserver in the relationship.
- peer_cluster:
- description:
- - Specifies name of the peer Cluster.
- - Required for creating the vserver peer relationship with a remote cluster
- dest_hostname:
- description:
- - Destination hostname or IP address.
- - Required for creating the vserver peer relationship with a remote cluster
- dest_username:
- description:
- - Destination username.
- - Optional if this is same as source username.
- dest_password:
- description:
- - Destination password.
- - Optional if this is same as source password.
-short_description: NetApp ONTAP Vserver peering
-version_added: "2.7"
-'''
-
-EXAMPLES = """
-
- - name: Source vserver peer create
- na_ontap_vserver_peer:
- state: present
- peer_vserver: ansible2
- peer_cluster: ansibleCluster
- vserver: ansible
- applications: snapmirror
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
- dest_hostname: "{{ netapp_dest_hostname }}"
-
- - name: vserver peer delete
- na_ontap_vserver_peer:
- state: absent
- peer_vserver: ansible2
- vserver: ansible
- hostname: "{{ netapp_hostname }}"
- username: "{{ netapp_username }}"
- password: "{{ netapp_password }}"
-"""
-
-RETURN = """
-"""
-
-import traceback
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-import ansible.module_utils.netapp as netapp_utils
-from ansible.module_utils.netapp_module import NetAppModule
-
-HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
-
-
-class NetAppONTAPVserverPeer(object):
- """
- Class with vserver peer methods
- """
-
- def __init__(self):
-
- self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
- self.argument_spec.update(dict(
- state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
- vserver=dict(required=True, type='str'),
- peer_vserver=dict(required=True, type='str'),
- peer_cluster=dict(required=False, type='str'),
- applications=dict(required=False, type='list', choices=['snapmirror', 'file_copy', 'lun_copy', 'flexcache']),
- dest_hostname=dict(required=False, type='str'),
- dest_username=dict(required=False, type='str'),
- dest_password=dict(required=False, type='str', no_log=True)
- ))
-
- self.module = AnsibleModule(
- argument_spec=self.argument_spec,
- supports_check_mode=True
- )
-
- self.na_helper = NetAppModule()
- self.parameters = self.na_helper.set_parameters(self.module.params)
-
- if HAS_NETAPP_LIB is False:
- self.module.fail_json(msg="the python NetApp-Lib module is required")
- else:
- self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- if self.parameters.get('dest_hostname'):
- self.module.params['hostname'] = self.parameters['dest_hostname']
- if self.parameters.get('dest_username'):
- self.module.params['username'] = self.parameters['dest_username']
- if self.parameters.get('dest_password'):
- self.module.params['password'] = self.parameters['dest_password']
- self.dest_server = netapp_utils.setup_na_ontap_zapi(module=self.module)
- # reset to source host connection for asup logs
- self.module.params['hostname'] = self.parameters['hostname']
-
- def vserver_peer_get_iter(self):
- """
- Compose NaElement object to query current vserver using peer-vserver and vserver parameters
- :return: NaElement object for vserver-get-iter with query
- """
- vserver_peer_get = netapp_utils.zapi.NaElement('vserver-peer-get-iter')
- query = netapp_utils.zapi.NaElement('query')
- vserver_peer_info = netapp_utils.zapi.NaElement('vserver-peer-info')
- vserver_peer_info.add_new_child('peer-vserver', self.parameters['peer_vserver'])
- vserver_peer_info.add_new_child('vserver', self.parameters['vserver'])
- query.add_child_elem(vserver_peer_info)
- vserver_peer_get.add_child_elem(query)
- return vserver_peer_get
-
- def vserver_peer_get(self):
- """
- Get current vserver peer info
- :return: Dictionary of current vserver peer details if query successful, else return None
- """
- vserver_peer_get_iter = self.vserver_peer_get_iter()
- vserver_info = dict()
- try:
- result = self.server.invoke_successfully(vserver_peer_get_iter, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching vserver peer %s: %s'
- % (self.parameters['vserver'], to_native(error)),
- exception=traceback.format_exc())
- # return vserver peer details
- if result.get_child_by_name('num-records') and \
- int(result.get_child_content('num-records')) > 0:
- vserver_peer_info = result.get_child_by_name('attributes-list').get_child_by_name('vserver-peer-info')
- vserver_info['peer_vserver'] = vserver_peer_info.get_child_content('peer-vserver')
- vserver_info['vserver'] = vserver_peer_info.get_child_content('vserver')
- vserver_info['peer_state'] = vserver_peer_info.get_child_content('peer-state')
- return vserver_info
- return None
-
- def vserver_peer_delete(self):
- """
- Delete a vserver peer
- """
- vserver_peer_delete = netapp_utils.zapi.NaElement.create_node_with_children(
- 'vserver-peer-delete', **{'peer-vserver': self.parameters['peer_vserver'],
- 'vserver': self.parameters['vserver']})
- try:
- self.server.invoke_successfully(vserver_peer_delete,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error deleting vserver peer %s: %s'
- % (self.parameters['vserver'], to_native(error)),
- exception=traceback.format_exc())
-
- def get_peer_cluster_name(self):
- """
- Get local cluster name
- :return: cluster name
- """
- cluster_info = netapp_utils.zapi.NaElement('cluster-identity-get')
- try:
- result = self.server.invoke_successfully(cluster_info, enable_tunneling=True)
- return result.get_child_by_name('attributes').get_child_by_name(
- 'cluster-identity-info').get_child_content('cluster-name')
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error fetching peer cluster name for peer vserver %s: %s'
- % (self.parameters['peer_vserver'], to_native(error)),
- exception=traceback.format_exc())
-
- def vserver_peer_create(self):
- """
- Create a vserver peer
- """
- if self.parameters.get('applications') is None:
- self.module.fail_json(msg='applications parameter is missing')
- if self.parameters.get('peer_cluster') is not None and self.parameters.get('dest_hostname') is None:
- self.module.fail_json(msg='dest_hostname is required for peering a vserver in remote cluster')
- if self.parameters.get('peer_cluster') is None:
- self.parameters['peer_cluster'] = self.get_peer_cluster_name()
- vserver_peer_create = netapp_utils.zapi.NaElement.create_node_with_children(
- 'vserver-peer-create', **{'peer-vserver': self.parameters['peer_vserver'],
- 'vserver': self.parameters['vserver'],
- 'peer-cluster': self.parameters['peer_cluster']})
- applications = netapp_utils.zapi.NaElement('applications')
- for application in self.parameters['applications']:
- applications.add_new_child('vserver-peer-application', application)
- vserver_peer_create.add_child_elem(applications)
- try:
- self.server.invoke_successfully(vserver_peer_create,
- enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error creating vserver peer %s: %s'
- % (self.parameters['vserver'], to_native(error)),
- exception=traceback.format_exc())
-
- def is_remote_peer(self):
- if self.parameters.get('dest_hostname') is None or \
- (self.parameters['dest_hostname'] == self.parameters['hostname']):
- return False
- return True
-
- def vserver_peer_accept(self):
- """
- Accept a vserver peer at destination
- """
- # peer-vserver -> remote (source vserver is provided)
- # vserver -> local (destination vserver is provided)
- vserver_peer_accept = netapp_utils.zapi.NaElement.create_node_with_children(
- 'vserver-peer-accept', **{'peer-vserver': self.parameters['vserver'],
- 'vserver': self.parameters['peer_vserver']})
- try:
- self.dest_server.invoke_successfully(vserver_peer_accept, enable_tunneling=True)
- except netapp_utils.zapi.NaApiError as error:
- self.module.fail_json(msg='Error accepting vserver peer %s: %s'
- % (self.parameters['peer_vserver'], to_native(error)),
- exception=traceback.format_exc())
-
- def apply(self):
- """
- Apply action to create/delete or accept vserver peer
- """
- results = netapp_utils.get_cserver(self.server)
- cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
- netapp_utils.ems_log_event("na_ontap_vserver_peer", cserver)
- current = self.vserver_peer_get()
- cd_action = self.na_helper.get_cd_action(current, self.parameters)
- if cd_action == 'create':
- self.vserver_peer_create()
- # accept only if the peer relationship is on a remote cluster
- if self.is_remote_peer():
- self.vserver_peer_accept()
- elif cd_action == 'delete':
- self.vserver_peer_delete()
-
- self.module.exit_json(changed=self.na_helper.changed)
-
-
-def main():
- """Execute action"""
- community_obj = NetAppONTAPVserverPeer()
- community_obj.apply()
-
-
-if __name__ == '__main__':
- main()