def set_cifs_homedirs(self, homedirs): """Set the list of CIFS home directory paths for the filer.""" homedir_paths = NaElement('homedir-paths') for d in homedirs: homedir_paths.child_add(NaElement('homedir-path-info', d)) chps = NaElement('cifs-homedir-paths-set') chps.child_add(homedir_paths) self.invoke_elem(chps)
def listSnapshots(volume): cmd = NaElement("snapshot-list-info") cmd.child_add_string("volume", volume) ret = executeCmd(cmd) return ret
def listSnapshots(volume): cmd = NaElement('snapshot-list-info') cmd.child_add_string('volume', volume) ret = executeCmd(cmd) return ret
def createClone(parentVolume, volume): cmd = NaElement("volume-clone-create") cmd.child_add_string("parent-volume", parentVolume) cmd.child_add_string("volume", volume) # Feature disabled for now debugret = NaElement("results") debugret.attr_set("status", "failed") debugret.attr_set("reason", "Creating clones not supported...yet!") return debugret
def get_volumes(conn): cmd = NaElement('volume-get-iter') cmd.child_add_string('max-records', 500) out = conn.invoke_elem(cmd) if(out.results_status() == 'failed'): print (out.results_reason() + '\n') sys.exit(2) attributes = out.child_get('attributes-list') return attributes.children_get()
def createSnapshot(volume, customname=None): if customname: snapshotName = customname else: # Create snapshot format name snapshotName = "snap_" + volume + "_" + datetime.strftime(datetime.now(), "%Y%m%d%H%M%S") cmd = NaElement("snapshot-create") cmd.child_add_string("volume", volume) cmd.child_add_string("snapshot", snapshotName) return executeCmd(cmd)
def renameSnapshot(volume, snapshot, newName): cmd = NaElement("snapshot-rename") cmd.child_add_string("current-name", snapshot) cmd.child_add_string("volume", volume) cmd.child_add_string("new-name", newName) return executeCmd(cmd)
def get_instance_list(self, perf_obj): ''' Lists instances associated with the supplied performance object. Some objects actually have instances, like 'volume' and 'aggregate', while others only have themselves (so sad...) like 'system' or 'cifs' ''' list_in = NaElement("perf-object-instance-list-info") list_in.child_add_string("objectname", perf_obj) out = self.invoke_elem(list_in) check_zapi_error(out) inst_info = out.child_get("instances") result = inst_info.children_get() instance_names = [] for inst in result: inst_name = inst.child_get_string("name") instance_names.append(inst_name) return instance_names
def set_snapshot_schedule(self, snap_sched): """@todo: Docstring for set_snapshot_schedule. :snap_sched: Dict that my contain one or more of the following keys: days, hours, minutes, weeks, which-hours, which-minutes :returns: @todo """ list_in = NaElement('snapshot-set-schedule') list_in.child_add_string('volume', self.name) for snap_interval, snap_count in snap_sched.iteritems(): list_in.child_add_string(snap_interval, snap_count) out = self.invoke_elem(list_in) check_zapi_error(out)
def invoke_cli(s, cli_args): """ Call the unsupported/undocumented system-cli API. cli_args, a list of commands, would represent the command line if executing in the CLI. Return the NaElement result of executing the command. """ args = NaElement('args') for arg in cli_args: args.child_add(NaElement('arg', arg)) cli = NaElement('system-cli') cli.child_add(args) out = s.invoke_elem(cli) if out.results_status() != 'passed': raise Exception(out.results_reason()) return out
def invoke_cli(self, *cli_args): """ Call the unsupported/undocumented system-cli API. args is a tuple of arguments that, joined with spaces, would represent the command line if executing in the CLI. """ args = NaElement('args') for arg in cli_args: args.child_add(NaElement('arg', arg)) cli = NaElement('system-cli') cli.child_add(args) out = self.api.invoke_elem(cli) if out.results_status() == 'failed': raise OntapApiException(out.results_errno(), out.results_reason()) return out
def dict_to_naelement(naelem_dict, parent_naelem=None): """ Generates an NaElement object from a dictionary, useful for API calls that require nested NaElement objects (like nfs exports) or for spoofing response objects. Note that the outermost dictionary can only contain one parent key and the optional attribute. """ attrs = None #if not parent_naelem and len(naelem_dict) > 2 and 'attrs' not in naelem_dict: # raise NetCrAPIOut('There can only be ONE (top level element)!') for k, v in naelem_dict.iteritems(): if k == 'attrs': attrs = v #print "attrs: " #print v continue else: if isinstance(v, dict): new_naelem = NaElement(k) if parent_naelem: parent_naelem.child_add(new_naelem) dict_to_naelement(v, new_naelem) elif isinstance(v, list): for item in v: new_naelem = NaElement(k) if parent_naelem: parent_naelem.child_add(new_naelem) dict_to_naelement(item, new_naelem) elif isinstance(v, str): if parent_naelem: parent_naelem.child_add_string(k, v) if not parent_naelem: if attrs: for k, v in attrs.iteritems(): new_naelem.attr_set(k, v) return new_naelem
def get_counter_list(self, perf_obj): ''' Returns the counters associated with a performance object. This function also outputs the 'base counter', 'privilege level' and 'unit' of the counter. ''' list_in = NaElement("perf-object-counter-list-info") list_in.child_add_string("objectname", perf_obj) out = self.invoke_elem(list_in) check_zapi_error(out) counter_info = out.child_get("counters") result = counter_info.children_get() counter_list = [] for counter in result: counter_name = counter.child_get_string("name") if counter.child_get_string("base-counter"): base_counter = counter.child_get_string("base-counter") else: base_counter = "None" privilege_level = counter.child_get_string("privilege-level") if counter.child_get_string("unit"): unit = counter.child_get_string("unit") else: unit = "None" if counter.child_get_string("properties"): counter_type = counter.child_get_string("properties") else: counter_type = "None" counter_list.append([counter_name, base_counter, counter_type, privilege_level, unit]) return counter_list
def invoke_cli(self, command): """Undocumented API that runs supplied arguments as a command. API documentation and python code found here: https://communities.netapp.com/message/74370 :command: @todo :returns: Object containing cli-output (string) and cli-result-value (integer) """ args = NaElement('args') for arg in command.split(): args.child_add(NaElement('arg', arg)) cli = NaElement('system-cli') cli.child_add(args) out = self.invoke_elem(cli) check_zapi_error(out) return out
perfGet = { # object names 'system': { # instances 'system': # counters [ 'serial_no', 'system_id', 'hostname', 'ontap_version', 'system_model' ], }, } server = ZenOntap('8.8.8.8', 'un', 'pw', 'HTTPS') request = NaElement('perf-object-get-instances') for perf, instances in perfGet.iteritems(): request.child_add_string('objectname', perf) reqinst = NaElement('instances') for instance, counters in instances.iteritems(): reqinst.child_add_string('instance', instance) reqcnts = NaElement('counters') for counter in counters: reqcnts.child_add_string('counter', counter) request.child_add(reqcnts) request.child_add(reqinst) response = server.invoke_elem_async(request) deferreds = [response] naElements = defer.DeferredList(deferreds, consumeErrors=True).addCallback(callback)
def get_info(self): """@todo: Docstring for get_info. :returns: @todo """ volume_info = {'volume-autosize-attributes': { 'maximum-size': 'integer', 'increment-size': 'integer', 'is-enabled': 'boolean' }, 'volume-id-attributes': { 'containing-aggregate-name': 'string', 'type': 'string', 'owning-vserver-name': 'string' }, 'volume-inode-attributes': { 'files-total': 'integer', 'files-used': 'integer', 'block-type': 'string' }, 'volume-state-attributes': { 'state': 'string' }, 'volume-space-attributes': { 'percentage-size-used': 'integer', 'size-total': 'integer', 'size-available': 'integer', 'size-used': 'integer', 'size-used-by-snapshots': 'integer', 'space-guarantee': 'string', 'size': 'integer', 'percentage-snapshot-reserve': 'integer', 'percentage-fractional-reserve': 'integer', }, 'volume-sis-attributes': { 'is-sis-volume': 'boolean', 'deduplication-space-saved': 'integer', 'compression-space-saved': 'integer', 'total-space-saved': 'integer' } } vol_get_iter = NaElement('volume-get-iter') query = NaElement('query') vol_query_attrs = NaElement('volume-attributes') vol_id_attrs = NaElement('volume-id-attributes') vol_get_iter.child_add(query) query.child_add(vol_query_attrs) vol_query_attrs.child_add(vol_id_attrs) vol_id_attrs.child_add_string('name', self.name) out = self.invoke_elem(vol_get_iter) attributes_list = out.child_get('attributes-list').children_get()[0] #print attributes_list.sprintf() vol_info_dict = {} for vol_attribute_type, attributes in volume_info.iteritems(): attribute_group = attributes_list.child_get(vol_attribute_type) for attr_name, data_type in attributes.iteritems(): #print vol_attribute_type #print attribute_group #print attr_name #print data_type if data_type == 'string': data = attribute_group.child_get_string(attr_name) vol_info_dict[attr_name] = data elif data_type == 'integer': data = attribute_group.child_get_int(attr_name) vol_info_dict[attr_name] = data elif data_type == 'boolean': data = (attribute_group.child_get_string(attr_name) == 'true') vol_info_dict[attr_name] = data return vol_info_dict
def set_sv_sec_snap_sched(self, sched, auto_update, retention_ct, dow = 'mon-sun', hod = '0'): """ Set the SnapVault snapshot schedule on a SnapVault secondary. sched - SnapVault schedule's name retention_ct - Number of snapshots to be retained dow - Days of week on which the schedule will run hod - Hours of day on whcih the schedule will run """ nae = NaElement('snapvault-secondary-set-snapshot-schedule') snap_sched = NaElement('snapshot-schedule') ssssi = NaElement('snapvault-secondary-snapshot-schedule-info') if auto_update: ssssi.child_add(NaElement('is-auto-update', 'true')) else: ssssi.child_add(NaElement('is-auto-update', 'false')) ssssi.child_add(NaElement('retention-count', int(retention_ct))) ssssi.child_add(NaElement('schedule-name', sched)) ssssi.child_add(NaElement('volume-name', self.name)) sched_info = NaElement('snapvault-schedule-info') sched_info.child_add(NaElement('days-of-week', dow)) sched_info.child_add(NaElement('hours-of_day', str(hod))) sched = NaElement('schedule') sched.child_add(sched_info) ssssi.child_add(sched) snap_sched.child_add(ssssi) nae.child_add(snap_sched) self.filer.invoke_elem(nae)
def create(self, aggr, size): """@todo: Docstring for create. :aggr: @todo :size: @todo :returns: @todo """ list_in = NaElement('volume-create') #name list_in.child_add_string("volume", self.name) #aggr list_in.child_add_string("containing-aggr-name", aggr) #size size_pattern = re.compile('^[1-9][0-9]*[kmgt]') if size_pattern.match(size): list_in.child_add_string("size", size) else: raise NetCrAPIOut("Size not valid. Please use <number>k|m|g|t.") pass #space reservation (none) list_in.child_add_string("space-reserve", "none") #language (en_US) list_in.child_add_string("language-code", "en_US") out = self.invoke_elem(list_in) check_zapi_error(out)
def delete_rule(self): """Remove the exportfs rule for a share.""" # # Construct NaElement tree: # pathname_info = NaElement('pathname-info') pathname_info.child_add(NaElement('name', self.path)) pathnames = NaElement('pathnames') pathnames.child_add(pathname_info) elem = NaElement('nfs-exportfs-delete-rules') elem.child_add(NaElement('persistent', 'true')) elem.child_add(pathnames) # Execute it: self.filer.invoke_elem(elem)
def modify_rule(self, nosuid=True, root_hosts=[], ro_hosts=[], rw_hosts=[], sec_flavor='sys'): """ Change the exportfs rule for an NFS share. This method follows the semantics of the NetApp API for default values, namely: 'By default, if no 'read-only' or 'read-write' hosts are given, then 'read-write' [access is granted to all hosts].' The exportfs rule must already exist before calling this method, or an exception will be thrown. """ # Parse arguments: if nosuid: nosuid_val = 'true' else: nosuid_val = 'false' # # Construct NaElement tree: # rule_info = NaElement('exports-rule-info') rule_info.child_add(NaElement('nosuid', nosuid_val)) rule_info.child_add(NaElement('pathname', self.path)) host_lists = { 'root': root_hosts, 'read-only': ro_hosts, 'read-write': rw_hosts } for elem in host_lists: if len(host_lists[elem]) > 0: nae = NaElement(elem) for host in host_lists[elem]: ehi = NaElement('exports-hostname-info') ehi.child_add(NaElement('name', host)) nae.child_add(ehi) rule_info.child_add(nae) nfs_export = NaElement('nfs-exportfs-modify-rule') nfs_export.child_add(NaElement('persistent', 'true')) rule = NaElement('rule') rule.child_add(rule_info) nfs_export.child_add(rule) # Execute rule change: self.filer.invoke_elem(nfs_export)
def get_perf_object(self, objectname, read=[], instances=[]): """ Return objectname's performance data in a dict tree. read - optional array of counters whose values are to be read. If not set, all counters are reported. instances - optional array of instances whose values are to be read. If not set, all instances are reported. """ info = self.get_perf_object_info(objectname) get_perf_obj = NaElement('perf-object-get-instances-iter-start') get_perf_obj.child_add(NaElement('objectname', objectname)) if read: read_counters = NaElement('counters') for c in read: read_counters.child_add(NaElement('counter', c)) get_perf_obj.child_add(read_counters) if instances: insts = NaElement('instances') for inst in instances: insts.child_add(NaElement('instance', inst)) get_perf_obj.child_add(insts) out = self.invoke_elem(get_perf_obj) iter_tag = out.child_get_int('tag') iter_recs = out.child_get_int('records') perf_insts = {} i = 0 while i < iter_recs: out = self.invoke('perf-object-get-instances-iter-next', 'maximum', 1, 'tag', iter_tag) inst = out.child_get('instances').child_get('instance-data') inst_name = inst.child_get_string('name') perf_insts[inst_name] = {} counters = inst.child_get('counters').children_get() for c in counters: name = c.child_get_string('name') if info[name]['type'] == 'array': vals = c.child_get_string('value').split(',') data = {} j = 0 while j < len(vals): data[info[name]['labels'][j]] = int(vals[j]) j = j + 1 perf_insts[inst_name][name] = data else: try: perf_insts[inst_name][name] = c.child_get_int('value') except ValueError: # Must be a string... perf_insts[inst_name][name] = c.child_get_string( 'value') i = i + 1 self.invoke('perf-object-get-instances-iter-end', 'tag', iter_tag) return perf_insts
def listVolumes(): isDebug = getConfigOption("Debug") # Build command to list volumes cmd = NaElement("volume-get-iter") xi = NaElement("desired-attributes") xi1 = NaElement("volume-attributes") xi1.child_add(NaElement("volume-id-attributes")) xi1.child_add(NaElement("volume-snapshot-attributes")) xi1.child_add(NaElement("volume-space-attributes")) xi2 = NaElement("volume-clone-attributes") xi2.child_add(NaElement("volume-clone-parent-attributes")) xi1.child_add(xi2) xi.child_add(xi1) cmd.child_add(xi) cmd.child_add_string("max-records", "500") ret = executeCmd(cmd) # Remove volumes from list that contain filterStrings filterString = getConfigOption("VolFilters") filterList = filterString.replace(" ", "").split(",") filteredVolumes = NaElement("attributes-list") for vol in ret.child_get("attributes-list").children_get(): volattrs = vol.child_get("volume-id-attributes") if any(x in volattrs.child_get_string("name") for x in filterList): if isDebug == "True": print "Skipping filtered vol : %s" % volattrs.child_get_string("name") continue if isDebug == "True": print "Volume Name : %s" % volattrs.child_get_string("name") filteredVolumes.child_add(vol) filteredRet = NaElement("results") filteredRet.attr_set("status", "passed") filteredRet.child_add(filteredVolumes) if isDebug == "True": print "Number of volumes (after filtering): " + str(ret.child_get("attributes-list").children_get().__len__()) return filteredRet
def set_sv_sec_snap_sched(self, sched, auto_update, retention_ct, dow='mon-sun', hod='0'): """ Set the SnapVault snapshot schedule on a SnapVault secondary. sched - SnapVault schedule's name retention_ct - Number of snapshots to be retained dow - Days of week on which the schedule will run hod - Hours of day on whcih the schedule will run """ nae = NaElement('snapvault-secondary-set-snapshot-schedule') snap_sched = NaElement('snapshot-schedule') ssssi = NaElement('snapvault-secondary-snapshot-schedule-info') if auto_update: ssssi.child_add(NaElement('is-auto-update', 'true')) else: ssssi.child_add(NaElement('is-auto-update', 'false')) ssssi.child_add(NaElement('retention-count', int(retention_ct))) ssssi.child_add(NaElement('schedule-name', sched)) ssssi.child_add(NaElement('volume-name', self.name)) sched_info = NaElement('snapvault-schedule-info') sched_info.child_add(NaElement('days-of-week', dow)) sched_info.child_add(NaElement('hours-of_day', str(hod))) sched = NaElement('schedule') sched.child_add(sched_info) ssssi.child_add(sched) snap_sched.child_add(ssssi) nae.child_add(snap_sched) self.filer.invoke_elem(nae)
def restoreSnapshot(volume, snapshot): cmd = NaElement("snapshot-restore-volume") cmd.child_add_string("snapshot", snapshot) cmd.child_add_string("volume", volume) return executeCmd(cmd)
def modify_rule(self, nosuid=True, root_hosts = [], ro_hosts = [], rw_hosts = [], sec_flavor = 'sys'): """ Change the exportfs rule for an NFS share. This method follows the semantics of the NetApp API for default values, namely: 'By default, if no 'read-only' or 'read-write' hosts are given, then 'read-write' [access is granted to all hosts].' The exportfs rule must already exist before calling this method, or an exception will be thrown. """ # Parse arguments: if nosuid: nosuid_val = 'true' else: nosuid_val = 'false' # # Construct NaElement tree: # rule_info = NaElement('exports-rule-info') rule_info.child_add(NaElement('nosuid', nosuid_val)) rule_info.child_add(NaElement('pathname', self.path)) host_lists = { 'root': root_hosts, 'read-only': ro_hosts, 'read-write': rw_hosts } for elem in host_lists: if len(host_lists[elem]) > 0: nae = NaElement(elem) for host in host_lists[elem]: ehi = NaElement('exports-hostname-info') ehi.child_add(NaElement('name', host)) nae.child_add(ehi) rule_info.child_add(nae) nfs_export = NaElement('nfs-exportfs-modify-rule') nfs_export.child_add(NaElement('persistent', 'true')) rule = NaElement('rule') rule.child_add(rule_info) nfs_export.child_add(rule) # Execute rule change: self.filer.invoke_elem(nfs_export)
def deleteSnapshot(volume, snapshot): cmd = NaElement('snapshot-delete') cmd.child_add_string("snapshot", snapshot) cmd.child_add_string("volume", volume) return executeCmd(cmd)