def _invoke_7mode_iterator_getter(self, start_api_name, next_api_name, end_api_name, record_container_tag_name, maximum=100): """Invoke a 7-mode iterator-style getter API.""" data = [] start_api = netapp_api.NaElement(start_api_name) start_result = self.connection.invoke_successfully(start_api) tag = start_result.get_child_content('tag') if not tag: return data try: while True: next_api = netapp_api.NaElement(next_api_name) next_api.add_new_child('tag', tag) next_api.add_new_child('maximum', six.text_type(maximum)) next_result = self.connection.invoke_successfully(next_api) records = next_result.get_child_content('records') or 0 if int(records) == 0: break record_container = next_result.get_child_by_name( record_container_tag_name) or netapp_api.NaElement('none') data.extend(record_container.get_children()) finally: end_api = netapp_api.NaElement(end_api_name) end_api.add_new_child('tag', tag) self.connection.invoke_successfully(end_api) return data
def _wait_for_clone_finish(self, clone_op_id, vol_uuid): """Waits till a clone operation is complete or errored out.""" clone_ls_st = netapp_api.NaElement('clone-list-status') clone_id = netapp_api.NaElement('clone-id') clone_ls_st.add_child_elem(clone_id) clone_id.add_node_with_children( 'clone-id-info', **{ 'clone-op-id': clone_op_id, 'volume-uuid': vol_uuid }) task_running = True while task_running: result = self.connection.invoke_successfully(clone_ls_st, enable_tunneling=True) status = result.get_child_by_name('status') ops_info = status.get_children() if ops_info: state = ops_info[0].get_child_content('clone-state') if state == 'completed': task_running = False elif state == 'failed': code = ops_info[0].get_child_content('error') reason = ops_info[0].get_child_content('reason') raise netapp_api.NaApiError(code, reason) else: time.sleep(1) else: raise netapp_api.NaApiError( 'UnknownCloneId', 'No clone operation for clone id %s found on the filer' % (clone_id))
def get_lun_map(self, path): """Gets the LUN map by LUN path.""" tag = None map_list = [] while True: lun_map_iter = netapp_api.NaElement('lun-map-get-iter') lun_map_iter.add_new_child('max-records', '100') if tag: lun_map_iter.add_new_child('tag', tag, True) query = netapp_api.NaElement('query') lun_map_iter.add_child_elem(query) query.add_node_with_children('lun-map-info', **{'path': path}) result = self.connection.invoke_successfully(lun_map_iter, True) tag = result.get_child_content('next-tag') if result.get_child_content('num-records') and \ int(result.get_child_content('num-records')) >= 1: attr_list = result.get_child_by_name('attributes-list') lun_maps = attr_list.get_children() for lun_map in lun_maps: lun_m = dict() lun_m['initiator-group'] = lun_map.get_child_content( 'initiator-group') lun_m['lun-id'] = lun_map.get_child_content('lun-id') lun_m['vserver'] = lun_map.get_child_content('vserver') map_list.append(lun_m) if tag is None: break return map_list
def get_vol_by_junc_vserver(self, vserver, junction): """Gets the volume by junction path and vserver.""" vol_iter = netapp_api.NaElement('volume-get-iter') vol_iter.add_new_child('max-records', '10') query = netapp_api.NaElement('query') vol_iter.add_child_elem(query) vol_attrs = netapp_api.NaElement('volume-attributes') query.add_child_elem(vol_attrs) vol_attrs.add_node_with_children( 'volume-id-attributes', **{ 'junction-path': junction, 'owning-vserver-name': vserver }) des_attrs = netapp_api.NaElement('desired-attributes') des_attrs.add_node_with_children('volume-attributes', **{'volume-id-attributes': None}) vol_iter.add_child_elem(des_attrs) result = self._invoke_vserver_api(vol_iter, vserver) num_records = result.get_child_content('num-records') if num_records and int(num_records) >= 1: attr_list = result.get_child_by_name('attributes-list') vols = attr_list.get_children() vol_id = vols[0].get_child_by_name('volume-id-attributes') return vol_id.get_child_content('name') msg_fmt = {'vserver': vserver, 'junction': junction} raise exception.NotFound( _("No volume on cluster with vserver " "%(vserver)s and junction path " "%(junction)s ") % msg_fmt)
def get_lun_list(self): """Gets the list of LUNs on filer. Gets the LUNs from cluster with vserver. """ luns = [] tag = None while True: api = netapp_api.NaElement('lun-get-iter') api.add_new_child('max-records', '100') if tag: api.add_new_child('tag', tag, True) lun_info = netapp_api.NaElement('lun-info') lun_info.add_new_child('vserver', self.vserver) query = netapp_api.NaElement('query') query.add_child_elem(lun_info) api.add_child_elem(query) result = self.connection.invoke_successfully(api, True) if result.get_child_by_name('num-records') and\ int(result.get_child_content('num-records')) >= 1: attr_list = result.get_child_by_name('attributes-list') luns.extend(attr_list.get_children()) tag = result.get_child_content('next-tag') if tag is None: break return luns
def _has_luns_mapped_to_initiator(self, initiator): """Checks whether any LUNs are mapped to the given initiator.""" lun_list_api = netapp_api.NaElement('lun-initiator-list-map-info') lun_list_api.add_new_child('initiator', initiator) result = self.connection.invoke_successfully(lun_list_api, True) lun_maps_container = result.get_child_by_name( 'lun-maps') or netapp_api.NaElement('none') return len(lun_maps_container.get_children()) > 0
def get_cserver_zapi(server): vserver_info = zapi.NaElement('vserver-get-iter') query_details = zapi.NaElement.create_node_with_children( 'vserver-info', **{'vserver-type': 'admin'}) query = zapi.NaElement('query') query.add_child_elem(query_details) vserver_info.add_child_elem(query) result = server.invoke_successfully(vserver_info, enable_tunneling=False) attribute_list = result.get_child_by_name('attributes-list') vserver_list = attribute_list.get_child_by_name('vserver-info') return vserver_list.get_child_content('vserver-name')
def get_lun_by_args(self, **args): """Retrieves LUN with specified args.""" lun_iter = netapp_api.NaElement('lun-get-iter') lun_iter.add_new_child('max-records', '100') query = netapp_api.NaElement('query') lun_iter.add_child_elem(query) query.add_node_with_children('lun-info', **args) luns = self.connection.invoke_successfully(lun_iter, True) attr_list = luns.get_child_by_name('attributes-list') if not attr_list: return [] return attr_list.get_children()
def get_if_info_by_ip(self, ip): """Gets the network interface info by ip.""" net_if_iter = netapp_api.NaElement('net-interface-get-iter') net_if_iter.add_new_child('max-records', '10') query = netapp_api.NaElement('query') net_if_iter.add_child_elem(query) query.add_node_with_children( 'net-interface-info', **{'address': na_utils.resolve_hostname(ip)}) result = self.connection.invoke_successfully(net_if_iter, True) num_records = result.get_child_content('num-records') if num_records and int(num_records) >= 1: attr_list = result.get_child_by_name('attributes-list') return attr_list.get_children() raise exception.NotFound( _('No interface found on cluster for ip %s') % ip)
def ems_log_event(source, server, name="Ansible", ident="12345", version=COLLECTION_VERSION, category="Information", event="setup", autosupport="false"): ems_log = zapi.NaElement('ems-autosupport-log') # Host name invoking the API. ems_log.add_new_child("computer-name", name) # ID of event. A user defined event-id, range [0..2^32-2]. ems_log.add_new_child("event-id", ident) # Name of the application invoking the API. ems_log.add_new_child("event-source", source) # Version of application invoking the API. ems_log.add_new_child("app-version", version) # Application defined category of the event. ems_log.add_new_child("category", category) # Description of event to log. An application defined message to log. ems_log.add_new_child("event-description", event) ems_log.add_new_child("log-level", "6") ems_log.add_new_child("auto-support", autosupport) try: server.invoke_successfully(ems_log, True) except zapi.NaApiError as exc: # Do not fail if we can't connect to the server. # The module will report a better error when trying to get some data from ONTAP. # Do not fail if we don't have write privileges. if not is_zapi_connection_error( exc.message) and not is_zapi_write_access_error(exc.message): # raise on other errors, as it may be a bug in calling the ZAPI raise exc
def _create_vs_get(): """Create vs_get API request.""" vs_get = netapp_api.NaElement('vserver-get-iter') vs_get.add_new_child('max-records', '1') query = netapp_api.NaElement('query') query.add_node_with_children('vserver-info', **{'vserver-type': 'node'}) vs_get.add_child_elem(query) desired = netapp_api.NaElement('desired-attributes') desired.add_node_with_children( 'vserver-info', **{ 'vserver-name': '', 'vserver-type': '' }) vs_get.add_child_elem(desired) return vs_get
def _get_vol_luns(self, vol_name): """Gets the LUNs for a volume.""" api = netapp_api.NaElement('lun-list-info') if vol_name: api.add_new_child('volume-name', vol_name) result = self.connection.invoke_successfully(api, True) luns = result.get_child_by_name('luns') return luns.get_children()
def get_filer_volumes(self, volume=None): """Returns list of filer volumes in API format.""" vol_request = netapp_api.NaElement('volume-list-info') res = self.connection.invoke_successfully(vol_request, True) volumes = res.get_child_by_name('volumes') if volumes: return volumes.get_children() return []
def clone_lun(self, volume, name, new_name, space_reserved='true', qos_policy_group_name=None, src_block=0, dest_block=0, block_count=0): # zAPI can only handle 2^24 blocks per range bc_limit = 2**24 # 8GB # zAPI can only handle 32 block ranges per call br_limit = 32 z_limit = br_limit * bc_limit # 256 GB z_calls = int(math.ceil(block_count / float(z_limit))) zbc = block_count if z_calls == 0: z_calls = 1 for _call in range(0, z_calls): if zbc > z_limit: block_count = z_limit zbc -= z_limit else: block_count = zbc clone_create = netapp_api.NaElement.create_node_with_children( 'clone-create', **{ 'volume': volume, 'source-path': name, 'destination-path': new_name, 'space-reserve': space_reserved }) if qos_policy_group_name is not None: clone_create.add_new_child('qos-policy-group-name', qos_policy_group_name) if block_count > 0: block_ranges = netapp_api.NaElement("block-ranges") segments = int(math.ceil(block_count / float(bc_limit))) bc = block_count for _segment in range(0, segments): if bc > bc_limit: block_count = bc_limit bc -= bc_limit else: block_count = bc block_range =\ netapp_api.NaElement.create_node_with_children( 'block-range', **{'source-block-number': six.text_type(src_block), 'destination-block-number': six.text_type(dest_block), 'block-count': six.text_type(block_count)}) block_ranges.add_child_elem(block_range) src_block += int(block_count) dest_block += int(block_count) clone_create.add_child_elem(block_ranges) self.connection.invoke_successfully(clone_create, True)
def check_apis_on_cluster(self, api_list=None): """Checks API availability and permissions on cluster. Checks API availability and permissions for executing user. Returns a list of failed apis. """ api_list = api_list or [] failed_apis = [] if api_list: api_version = self.connection.get_api_version() if api_version: major, minor = api_version if major == 1 and minor < 20: for api_name in api_list: na_el = netapp_api.NaElement(api_name) try: self.connection.invoke_successfully(na_el) except Exception as e: if isinstance(e, netapp_api.NaApiError): if (e.code == netapp_error.EAPINOTFOUND or e.code == netapp_error.EAPIPRIVILEGE): failed_apis.append(api_name) elif major == 1 and minor >= 20: failed_apis = copy.copy(api_list) result = netapp_api.invoke_api( self.connection, api_name='system-user-capability-get-iter', api_family='cm', additional_elems=None, is_iter=True) for res in result: attr_list = res.get_child_by_name('attributes-list') if attr_list: capabilities = attr_list.get_children() for capability in capabilities: op_list = capability.get_child_by_name( 'operation-list') if op_list: ops = op_list.get_children() for op in ops: apis = op.get_child_content('api-name') if apis: api_list = apis.split(',') for api_name in api_list: if (api_name and api_name.strip() in failed_apis): failed_apis.remove( api_name) else: continue else: msg = _("Unsupported Clustered Data ONTAP version.") raise exception.VolumeBackendAPIException(data=msg) else: msg = _("Data ONTAP API version could not be determined.") raise exception.VolumeBackendAPIException(data=msg) return failed_apis
def get_volume_options(self, volume_name): """Get the value for the volume option.""" opts = [] vol_option_list = netapp_api.NaElement("volume-options-list-info") vol_option_list.add_new_child('volume', volume_name) result = self.connection.invoke_successfully(vol_option_list, True) options = result.get_child_by_name("options") if options: opts = options.get_children() return opts
def get_iscsi_service_details(self): """Returns iscsi iqn.""" iscsi_service_iter = netapp_api.NaElement('iscsi-service-get-iter') result = self.connection.invoke_successfully(iscsi_service_iter, True) if result.get_child_content('num-records') and\ int(result.get_child_content('num-records')) >= 1: attr_list = result.get_child_by_name('attributes-list') iscsi_service = attr_list.get_child_by_name('iscsi-service-info') return iscsi_service.get_child_content('node-name') LOG.debug('No iSCSI service found for vserver %s', self.vserver) return None
def get_fc_target_wwpns(self): """Gets the FC target details.""" wwpns = [] port_name_list_api = netapp_api.NaElement('fcp-port-name-list-info') result = self.connection.invoke_successfully(port_name_list_api) port_names = result.get_child_by_name('fcp-port-names') if port_names: for port_name_info in port_names.get_children(): wwpn = port_name_info.get_child_content('port-name').lower() wwpns.append(wwpn) return wwpns
def get_ontapi_version(self, cached=True): """Gets the supported ontapi version.""" if cached: return self.connection.get_api_version() ontapi_version = netapp_api.NaElement('system-get-ontapi-version') res = self.connection.invoke_successfully(ontapi_version, False) major = res.get_child_content('major-version') minor = res.get_child_content('minor-version') return major, minor
def move_lun(self, path, new_path): """Moves the LUN at path to new path.""" seg = path.split("/") new_seg = new_path.split("/") LOG.debug("Moving LUN %(name)s to %(new_name)s.", { 'name': seg[-1], 'new_name': new_seg[-1] }) lun_move = netapp_api.NaElement("lun-move") lun_move.add_new_child("path", path) lun_move.add_new_child("new-path", new_path) self.connection.invoke_successfully(lun_move, True)
def _get_igroup_by_initiator_query(self, initiator, tag): igroup_get_iter = netapp_api.NaElement('igroup-get-iter') igroup_get_iter.add_new_child('max-records', '100') if tag: igroup_get_iter.add_new_child('tag', tag, True) query = netapp_api.NaElement('query') igroup_info = netapp_api.NaElement('initiator-group-info') query.add_child_elem(igroup_info) igroup_info.add_new_child('vserver', self.vserver) initiators = netapp_api.NaElement('initiators') igroup_info.add_child_elem(initiators) igroup_get_iter.add_child_elem(query) initiators.add_node_with_children('initiator-info', **{'initiator-name': initiator}) # limit results to just the attributes of interest desired_attrs = netapp_api.NaElement('desired-attributes') desired_igroup_info = netapp_api.NaElement('initiator-group-info') desired_igroup_info.add_node_with_children('initiators', **{'initiator-info': None}) desired_igroup_info.add_new_child('vserver', None) desired_igroup_info.add_new_child('initiator-group-name', None) desired_igroup_info.add_new_child('initiator-group-type', None) desired_igroup_info.add_new_child('initiator-group-os-type', None) desired_attrs.add_child_elem(desired_igroup_info) igroup_get_iter.add_child_elem(desired_attrs) return igroup_get_iter
def _check_clone_status(self, clone_id, vol_uuid, name, new_name): """Checks for the job till completed.""" clone_status = netapp_api.NaElement('clone-list-status') cl_id = netapp_api.NaElement('clone-id') clone_status.add_child_elem(cl_id) cl_id.add_node_with_children( 'clone-id-info', **{ 'clone-op-id': clone_id, 'volume-uuid': vol_uuid }) running = True clone_ops_info = None while running: result = self.connection.invoke_successfully(clone_status, True) status = result.get_child_by_name('status') ops_info = status.get_children() if ops_info: for info in ops_info: if info.get_child_content('clone-state') == 'running': time.sleep(1) break else: running = False clone_ops_info = info break else: if clone_ops_info: fmt = {'name': name, 'new_name': new_name} if clone_ops_info.get_child_content('clone-state')\ == 'completed': LOG.debug( "Clone operation with src %(name)s" " and dest %(new_name)s completed", fmt) else: LOG.debug( "Clone operation with src %(name)s" " and dest %(new_name)s failed", fmt) raise netapp_api.NaApiError( clone_ops_info.get_child_content('error'), clone_ops_info.get_child_content('reason'))
def get_cserver_zapi(server): ''' returns None if not run on the management or cluster IP ''' vserver_info = zapi.NaElement('vserver-get-iter') query_details = zapi.NaElement.create_node_with_children('vserver-info', **{'vserver-type': 'admin'}) query = zapi.NaElement('query') query.add_child_elem(query_details) vserver_info.add_child_elem(query) try: result = server.invoke_successfully(vserver_info, enable_tunneling=False) except zapi.NaApiError as exc: # Do not fail if we can't connect to the server. # The module will report a better error when trying to get some data from ONTAP. if is_zapi_connection_error(exc.message): return None # raise on other errors, as it may be a bug in calling the ZAPI raise exc attribute_list = result.get_child_by_name('attributes-list') if attribute_list is not None: vserver_list = attribute_list.get_child_by_name('vserver-info') if vserver_list is not None: return vserver_list.get_child_content('vserver-name') return None
def get_igroup_by_initiators(self, initiator_list): """Get igroups exactly matching a set of initiators.""" igroup_list = [] if not initiator_list: return igroup_list initiator_set = set(initiator_list) igroup_list_info = netapp_api.NaElement('igroup-list-info') result = self.connection.invoke_successfully(igroup_list_info, True) initiator_groups = result.get_child_by_name( 'initiator-groups') or netapp_api.NaElement('none') for initiator_group_info in initiator_groups.get_children(): initiator_set_for_igroup = set() initiators = initiator_group_info.get_child_by_name( 'initiators') or netapp_api.NaElement('none') for initiator_info in initiators.get_children(): initiator_set_for_igroup.add( initiator_info.get_child_content('initiator-name')) if initiator_set == initiator_set_for_igroup: igroup = { 'initiator-group-os-type': initiator_group_info.get_child_content( 'initiator-group-os-type'), 'initiator-group-type': initiator_group_info.get_child_content( 'initiator-group-type'), 'initiator-group-name': initiator_group_info.get_child_content( 'initiator-group-name') } igroup_list.append(igroup) return igroup_list
def get_iscsi_target_details(self): """Gets the iSCSI target portal details.""" iscsi_if_iter = netapp_api.NaElement('iscsi-portal-list-info') result = self.connection.invoke_successfully(iscsi_if_iter, True) tgt_list = [] portal_list_entries = result.get_child_by_name( 'iscsi-portal-list-entries') if portal_list_entries: portal_list = portal_list_entries.get_children() for iscsi_if in portal_list: d = dict() d['address'] = iscsi_if.get_child_content('ip-address') d['port'] = iscsi_if.get_child_content('ip-port') d['tpgroup-tag'] = iscsi_if.get_child_content('tpgroup-tag') tgt_list.append(d) return tgt_list
def ems_log_event(source, server, name="Ansible", id="12345", version="1.1", category="Information", event="setup", autosupport="false"): ems_log = zapi.NaElement('ems-autosupport-log') # Host name invoking the API. ems_log.add_new_child("computer-name", name) # ID of event. A user defined event-id, range [0..2^32-2]. ems_log.add_new_child("event-id", id) # Name of the application invoking the API. ems_log.add_new_child("event-source", source) # Version of application invoking the API. ems_log.add_new_child("app-version", version) # Application defined category of the event. ems_log.add_new_child("category", category) # Description of event to log. An application defined message to log. ems_log.add_new_child("event-description", event) ems_log.add_new_child("log-level", "6") ems_log.add_new_child("auto-support", autosupport) server.invoke_successfully(ems_log, True)
def get_fc_target_wwpns(self): """Gets the FC target details.""" wwpns = [] port_name_list_api = netapp_api.NaElement('fcp-port-name-get-iter') port_name_list_api.add_new_child('max-records', '100') result = self.connection.invoke_successfully(port_name_list_api, True) num_records = result.get_child_content('num-records') if num_records and int(num_records) >= 1: for port_name_info in result.get_child_by_name( 'attributes-list').get_children(): if port_name_info.get_child_content('is-used') != 'true': continue wwpn = port_name_info.get_child_content('port-name').lower() wwpns.append(wwpn) return wwpns
def get_iscsi_target_details(self): """Gets the iSCSI target portal details.""" iscsi_if_iter = netapp_api.NaElement('iscsi-interface-get-iter') result = self.connection.invoke_successfully(iscsi_if_iter, True) tgt_list = [] num_records = result.get_child_content('num-records') if num_records and int(num_records) >= 1: attr_list = result.get_child_by_name('attributes-list') iscsi_if_list = attr_list.get_children() for iscsi_if in iscsi_if_list: d = dict() d['address'] = iscsi_if.get_child_content('ip-address') d['port'] = iscsi_if.get_child_content('ip-port') d['tpgroup-tag'] = iscsi_if.get_child_content('tpgroup-tag') d['interface-enabled'] = iscsi_if.get_child_content( 'is-interface-enabled') tgt_list.append(d) return tgt_list
def _create_ems(netapp_backend, app_version, server_type): """Create ems API request.""" ems_log = netapp_api.NaElement('ems-autosupport-log') host = socket.getfqdn() or 'Cinder_node' if server_type == "cluster": dest = "cluster node" else: dest = "7 mode controller" ems_log.add_new_child('computer-name', host) ems_log.add_new_child('event-id', '0') ems_log.add_new_child('event-source', 'Cinder driver %s' % netapp_backend) ems_log.add_new_child('app-version', app_version) ems_log.add_new_child('category', 'provisioning') ems_log.add_new_child('event-description', 'OpenStack Cinder connected to %s' % dest) ems_log.add_new_child('log-level', '6') ems_log.add_new_child('auto-support', 'false') return ems_log
def get_lun_geometry(self, path): """Gets the LUN geometry.""" geometry = {} lun_geo = netapp_api.NaElement("lun-get-geometry") lun_geo.add_new_child('path', path) try: result = self.connection.invoke_successfully(lun_geo, True) geometry['size'] = result.get_child_content("size") geometry['bytes_per_sector'] =\ result.get_child_content("bytes-per-sector") geometry['sectors_per_track'] =\ result.get_child_content("sectors-per-track") geometry['tracks_per_cylinder'] =\ result.get_child_content("tracks-per-cylinder") geometry['cylinders'] =\ result.get_child_content("cylinders") geometry['max_resize'] =\ result.get_child_content("max-resize-size") except Exception as e: LOG.error(_LE("LUN %(path)s geometry failed. Message - %(msg)s"), { 'path': path, 'msg': e.message }) return geometry