Пример #1
0
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(
                state=dict(required=False,
                           choices=['present', 'absent'],
                           default='present'),
                service_state=dict(required=False,
                                   choices=['online', 'offline']),
                name=dict(required=True, type='str'),
                from_name=dict(required=False, type='str'),
                disk_count=dict(required=False, type='int', default=None),
                disk_type=dict(required=False,
                               choices=[
                                   'ATA', 'BSAS', 'FCAL', 'FSAS', 'LUN',
                                   'MSATA', 'SAS', 'SSD', 'VMDISK'
                               ]),
                raid_type=dict(required=False, type='str'),
                disk_size=dict(required=False, type='int'),
                nodes=dict(required=False, type='list'),
                raid_size=dict(required=False, type='int'),
                unmount_volumes=dict(required=False, type='bool'),
            ))

        self.module = AnsibleModule(argument_spec=self.argument_spec,
                                    required_if=[('service_state', 'offline',
                                                  ['unmount_volumes'])],
                                    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 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)
        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":
                return None
            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'])
        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)

        try:
            self.server.invoke_successfully(aggr_create,
                                            enable_tunneling=False)
        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)
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)
Пример #3
0
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', 'volume'], default=None),
            percent_snapshot_space=dict(type='str', 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'),
        ))
        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 self.parameters.get('size'):
            self.parameters['size'] = self.parameters['size'] * \
                self._size_unit_map[self.parameters['size_unit']]
        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_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.get_child_by_name(
                'attributes-list').get_child_by_name(
                    'volume-attributes')
            # Get volume's current size
            volume_space_attributes = volume_attributes.get_child_by_name(
                'volume-space-attributes')
            current_size = int(volume_space_attributes.get_child_content('size'))

            # Get volume's state (online/offline)
            volume_state_attributes = volume_attributes.get_child_by_name(
                'volume-state-attributes')
            current_state = volume_state_attributes.get_child_content('state')
            volume_id_attributes = volume_attributes.get_child_by_name(
                'volume-id-attributes')
            aggregate_name = volume_id_attributes.get_child_content(
                'containing-aggregate-name')
            volume_export_attributes = volume_attributes.get_child_by_name(
                'volume-export-attributes')
            policy = volume_export_attributes.get_child_content('policy')
            space_guarantee = volume_space_attributes.get_child_content(
                'space-guarantee')

            is_online = (current_state == "online")
            return_value = {
                'name': vol_name,
                'size': current_size,
                'is_online': is_online,
                'aggregate_name': aggregate_name,
                'policy': policy,
                'space_guarantee': space_guarantee,
            }

        return return_value

    def create_volume(self):
        '''Create ONTAP volume'''
        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 = {'volume': self.parameters['name'],
                   'containing-aggr-name': self.parameters['aggregate_name'],
                   'size': str(self.parameters['size'])}
        if self.parameters.get('percent_snapshot_space'):
            options['percentage-snapshot-reserve'] = self.parameters['percent_snapshot_space']
        if self.parameters.get('type'):
            options['volume-type'] = self.parameters['type']
        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('space_guarantee'):
            options['space-reserve'] = self.parameters['space_guarantee']
        if self.parameters.get('volume_security_style'):
            options['volume-security-style'] = self.parameters['volume_security_style']
        volume_create = netapp_utils.zapi.NaElement.create_node_with_children('volume-create', **options)
        try:
            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())

    def delete_volume(self):
        '''Delete ONTAP volume'''
        if self.parameters.get('is_infinite'):
            volume_delete = netapp_utils.zapi\
                .NaElement.create_node_with_children(
                    'volume-destroy-async', **{'volume-name': self.parameters['name']})
        else:
            volume_delete = netapp_utils.zapi\
                .NaElement.create_node_with_children(
                    'volume-destroy', **{'name': self.parameters['name'],
                                         'unmount-and-offline': 'true'})
        try:
            self.server.invoke_successfully(volume_delete, enable_tunneling=True)
            self.ems_log_event("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.
        """
        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:
            self.server.invoke_successfully(volume_rename,
                                            enable_tunneling=True)
            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']\
            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:
            self.server.invoke_successfully(volume_resize, enable_tunneling=True)
            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 = ['volume-online-async', 'volume-name'] if self.parameters['is_infinite']\
                else ['volume-online', 'name']
        else:   # Desired state is offline, setup zapi APIs respectively
            vol_state_zapi, vol_name_zapi = ['volume-offline-async', 'volume-name'] if self.parameters['is_infinite']\
                else ['volume-offline', 'name']
            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)
            self.server.invoke_successfully(volume_change_state, enable_tunneling=True)
            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 volume_modify_policy_space(self):
        """
        modify volume parameter 'policy' or 'space_guarantee'
        """
        # TODO: refactor this method
        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')
        if self.parameters.get('policy'):
            vol_export_attributes = netapp_utils.zapi.NaElement(
                'volume-export-attributes')
            vol_export_attributes.add_new_child('policy', self.parameters['policy'])
            vol_mod_attributes.add_child_elem(vol_export_attributes)
        if self.parameters.get('space_guarantee'):
            vol_space_attributes = netapp_utils.zapi.NaElement(
                'volume-space-attributes')
            vol_space_attributes.add_new_child(
                'space-guarantee', self.parameters['space_guarantee'])
            vol_mod_attributes.add_child_elem(vol_space_attributes)
        attributes.add_child_elem(vol_mod_attributes)
        query = netapp_utils.zapi.NaElement('query')
        vol_query_attributes = netapp_utils.zapi.NaElement('volume-attributes')
        vol_id_attributes = netapp_utils.zapi.NaElement('volume-id-attributes')
        vol_id_attributes.add_new_child('name', self.parameters['name'])
        vol_query_attributes.add_child_elem(vol_id_attributes)
        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')
            # handle error if modify space or policy parameter fails
            if failures is not None and failures.get_child_by_name('volume-modify-iter-info') is not None:
                error_msg = failures.get_child_by_name('volume-modify-iter-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 modify_volume(self, modify):
        for attribute in modify.keys():
            if attribute == 'size':
                self.resize_volume()
            elif attribute == 'is_online':
                self.change_volume_state()
            elif attribute == 'aggregate_name':
                self.move_volume()
            else:
                self.volume_modify_policy_space()

    def apply(self):
        '''Call create/modify/delete operations'''
        current = self.get_volume()
        # 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_volume(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_volume()
                if cd_action == 'create':
                    self.create_volume()
                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 == 'delete':
            message = "A Volume has been deleted"
        elif state == 'move':
            message = "A Volume has been moved"
        elif state == 'rename':
            message = "A Volume has been renamed"
        elif state == 'resize':
            message = "A Volume has been resized to: " + \
                str(self.parameters['size']) + str(self.parameters['size_unit'])
        elif state == '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)
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)
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)
Пример #6
0
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 broadcas 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)
Пример #7
0
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)
Пример #8
0
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 after creation, since vserver-create doesn't allow this attribute during creation
        if self.parameters.get('allowed_protocols'):
            self.modify_vserver(
                {'allowed_protocols': self.parameters['allowed_protocols']})

    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)
Пример #9
0
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)))
        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_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']
            # 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']
            }
            if volume_space_attributes.get_child_by_name(
                    'percentage-snapshot-reserve'):
                return_value[
                    'percent_snapshot_space'] = volume_space_attributes[
                        'percentage-snapshot-reserve']
            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('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

        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):
        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']
            if self.parameters.get('size'):
                options['size'] = str(self.parameters['size'])
        else:
            options['volume'] = self.parameters['name']
            options['size'] = str(self.parameters['size'])
            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('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('type'):
            options['volume-type'] = self.parameters['type']
        if self.parameters.get('percent_snapshot_space'):
            options['percentage-snapshot-reserve'] = self.parameters[
                'percent_snapshot_space']
        if self.parameters.get('language'):
            options['language-code'] = self.parameters['language']
        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 volume_modify_attributes(self):
        """
        modify volume parameter 'policy','unix_permissions','snapshot_policy','space_guarantee','percent_snapshot_space'
        """
        # TODO: refactor this method
        vol_mod_iter = None
        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')
        vol_space_attributes = netapp_utils.zapi.NaElement(
            'volume-space-attributes')
        if self.parameters.get('policy'):
            vol_export_attributes = netapp_utils.zapi.NaElement(
                'volume-export-attributes')
            vol_export_attributes.add_new_child('policy',
                                                self.parameters['policy'])
            vol_mod_attributes.add_child_elem(vol_export_attributes)
        if self.parameters.get('space_guarantee'):
            vol_space_attributes.add_new_child(
                'space-guarantee', self.parameters['space_guarantee'])
            vol_mod_attributes.add_child_elem(vol_space_attributes)
        if self.parameters.get('percent_snapshot_space'):
            vol_space_attributes.add_new_child(
                'percentage-snapshot-reserve',
                str(self.parameters['percent_snapshot_space']))
            vol_mod_attributes.add_child_elem(vol_space_attributes)
        if self.parameters.get('unix_permissions'):
            vol_unix_permissions_attributes = netapp_utils.zapi.NaElement(
                'volume-security-unix-attributes')
            vol_unix_permissions_attributes.add_new_child(
                'permissions', self.parameters['unix_permissions'])
            vol_security_attributes = netapp_utils.zapi.NaElement(
                'volume-security-attributes')
            vol_security_attributes.add_child_elem(
                vol_unix_permissions_attributes)
            vol_mod_attributes.add_child_elem(vol_security_attributes)
        if self.parameters.get('snapshot_policy') or self.parameters.get(
                'snapdir_access'):
            vol_snapshot_policy_attributes = netapp_utils.zapi.NaElement(
                'volume-snapshot-attributes')
            if self.parameters.get('snapshot_policy'):
                vol_snapshot_policy_attributes.add_new_child(
                    'snapshot-policy', self.parameters['snapshot_policy'])
            if self.parameters.get('snapdir_access'):
                vol_snapshot_policy_attributes.add_new_child(
                    'snapdir-access-enabled',
                    self.parameters.get('snapdir_access'))
            vol_mod_attributes.add_child_elem(vol_snapshot_policy_attributes)
        if self.parameters.get('atime_update'):
            vol_performance_attributes = netapp_utils.zapi.NaElement(
                'volume-performance-attributes')
            vol_performance_attributes.add_new_child(
                'is-atime-update-enabled', self.parameters.get('atime_update'))
            vol_mod_attributes.add_child_elem(vol_performance_attributes)
        attributes.add_child_elem(vol_mod_attributes)
        query = netapp_utils.zapi.NaElement('query')
        vol_query_attributes = netapp_utils.zapi.NaElement('volume-attributes')
        vol_id_attributes = netapp_utils.zapi.NaElement('volume-id-attributes')
        vol_id_attributes.add_new_child('name', self.parameters['name'])
        vol_query_attributes.add_child_elem(vol_id_attributes)
        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):
        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',
                    'snapshot_policy', 'percent_snapshot_space',
                    'snapdir_access', 'atime_update'
            ]:
                self.volume_modify_attributes()
            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):
        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())
        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']
        results = self.get_job(jobid, server)

        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):
        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):
        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 = 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 self.parameters.get('percent_snapshot_space'):
            self.parameters['percent_snapshot_space'] = str(
                self.parameters['percent_snapshot_space'])
        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()
                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)
Пример #10
0
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)
Пример #11
0
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)
class NetAppAWSCVS(object):
    '''Class  for  Pool operations '''

    def __init__(self):
        """
        Parse arguments, setup state variables,
        """
        self.argument_spec = netapp_utils.aws_cvs_host_argument_spec()
        self.argument_spec.update(dict(
            state=dict(required=True, choices=['present', 'absent']),
            region=dict(required=True, type='str'),
            name=dict(required=True, type='str'),
            from_name=dict(required=False, type='str'),
            serviceLevel=dict(required=False, choices=['basic', 'standard', 'extreme'], type='str'),
            sizeInBytes=dict(required=False, type='int'),
            vendorID=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)
        self.restApi = AwsCvsRestAPI(self.module)
        self.sizeInBytes_min_value = 4000000000000

    def get_aws_netapp_cvs_pool(self, name=None):
        """
        Returns Pool object if exists else Return None
        """
        pool_info = None

        if name is None:
            name = self.parameters['name']

        pools, error = self.restApi.get('Pools')

        if error is None and pools is not None:
            for pool in pools:
                if 'name' in pool and pool['region'] == self.parameters['region']:
                    if pool['name'] == name:
                        pool_info = pool
                        break

        return pool_info

    def create_aws_netapp_cvs_pool(self):
        """
        Create a pool
        """
        api = 'Pools'

        for key in ['serviceLevel', 'sizeInBytes', 'vendorID']:
            if key not in self.parameters.keys() or self.parameters[key] is None:
                self.module.fail_json(changed=False, msg="Mandatory key '%s' required" % (key))

        pool = {
            "name": self.parameters['name'],
            "region": self.parameters['region'],
            "serviceLevel": self.parameters['serviceLevel'],
            "sizeInBytes": self.parameters['sizeInBytes'],
            "vendorID": self.parameters['vendorID']
        }

        response, error = self.restApi.post(api, pool)
        if error is not None:
            self.module.fail_json(changed=False, msg=error)

    def update_aws_netapp_cvs_pool(self, update_pool_info, pool_id):
        """
        Update a pool
        """
        api = 'Pools/' + pool_id

        pool = {
            "name": update_pool_info['name'],
            "region": self.parameters['region'],
            "serviceLevel": update_pool_info['serviceLevel'],
            "sizeInBytes": update_pool_info['sizeInBytes'],
            "vendorID": update_pool_info['vendorID']
        }

        response, error = self.restApi.put(api, pool)
        if error is not None:
            self.module.fail_json(changed=False, msg=error)

    def delete_aws_netapp_cvs_pool(self, pool_id):
        """
        Delete a pool
        """
        api = 'Pools/' + pool_id
        data = None
        response, error = self.restApi.delete(api, data)

        if error is not None:
            self.module.fail_json(changed=False, msg=error)

    def apply(self):
        """
        Perform pre-checks, call functions and exit
        """
        update_required = False
        cd_action = None

        if 'sizeInBytes' in self.parameters.keys() and self.parameters['sizeInBytes'] < self.sizeInBytes_min_value:
            self.module.fail_json(changed=False, msg="sizeInBytes should be greater than  or equal to %d" % (self.sizeInBytes_min_value))

        current = self.get_aws_netapp_cvs_pool()
        if self.parameters.get('from_name'):
            existing = self.get_aws_netapp_cvs_pool(self.parameters['from_name'])
            rename = self.na_helper.is_rename_action(existing, current)
            if rename is None:
                self.module.fail_json(changed=False, msg="unable to rename pool: '%s' does not exist" % self.parameters['from_name'])
            if rename:
                current = existing
        else:
            cd_action = self.na_helper.get_cd_action(current, self.parameters)

        if cd_action is None and self.parameters['state'] == 'present':
            keys_to_check = ['name', 'vendorID', 'sizeInBytes', 'serviceLevel']
            update_pool_info, update_required = self.na_helper.compare_and_update_values(current, self.parameters, keys_to_check)

            if update_required is True:
                self.na_helper.changed = True
                cd_action = 'update'

        if self.na_helper.changed:
            if self.module.check_mode:
                pass
            else:
                if cd_action == 'update':
                    self.update_aws_netapp_cvs_pool(update_pool_info, current['poolId'])
                elif cd_action == 'create':
                    self.create_aws_netapp_cvs_pool()
                elif cd_action == 'delete':
                    self.delete_aws_netapp_cvs_pool(current['poolId'])

        self.module.exit_json(changed=self.na_helper.changed)