Beispiel #1
0
class ClusterSession:
    def __init__(self, cluster_ip, user, password, vserver=None):
        self.server = NaServer(cluster_ip, 1, 100)
        self.server.set_server_type('FILER')
        self.server.set_transport_type('HTTP')
        self.server.set_port(80)
        self.server.set_style('LOGIN')
        self.server.set_admin_user(user, password)
        if vserver is not None:
            self.server.set_vserver(vserver)

    def get_vserver(self):
        return self.server.get_vserver()

    def run_command(self, api):
        return self.server.invoke_elem(api)

    def get_nodes(self):
        api_call = NaElement('cluster-node-get-iter')
        output = self.run_command(api_call)
        if output.results_status() == 'failed':
            return output.results_status(), output.sprintf()
        else:
            cluster_node_info = output.children_get()
            for cni in cluster_node_info:
                if cni.has_children() == 1:
                    nodes = cni.children_get()
                    nodes_list = []
                    for n in nodes:
                        nodes_list.append(n.child_get_string('node-name'))
            return nodes_list
def connect():
    naHost = getConfigOption("NAHost")
    user = getConfigOption("User")
    password = getConfigOption("Password")
    s = NaServer(naHost, 1 , 21)
    s.set_server_type("FILER")
    s.set_transport_type("HTTPS")
    s.set_port(443)
    s.set_style("LOGIN")
    s.set_admin_user(user, password)
    return s
Beispiel #3
0
    def __create_server(self, testing_active):
        if testing_active:
            return None

        s = NaServer(
                self.host,
                self.ontap_major_version,
                self.ontap_minor_version)
        s.set_server_type(self.server_type)
        s.set_transport_type(self.transport_type)
        s.set_port(self.server_port)
        s.set_style(self.connect_style)
        s.set_admin_user(self.user, self.pwd)
    
        return s
def connect():
    try:
        _create_unverified_https_context = ssl._create_unverified_context
    except AttributeError:
        # Legacy Python that doesn't verify HTTPS certificates by default
        pass
    else:
        # Handle target environment that doesn't support HTTPS verification
        ssl._create_default_https_context = _create_unverified_https_context
    naHost = getConfigOption("NAHost")
    user = getConfigOption("User")
    password = getConfigOption("Password")
    s = NaServer(naHost, 1, 21)
    s.set_server_type("FILER")
    s.set_transport_type("HTTPS")
    s.set_port(443)
    s.set_style("LOGIN")
    s.set_admin_user(user, password)
    return s
Beispiel #5
0
 def __init__(self, filer_name, user, password, transport_type='HTTPS', apiversion=(1,19)):
     '''
     Creates the connection to the filer. Transport_type defaults to 'HTTPS'.
     Todo:
         Allow different connection styles?
     '''
     conn = NaServer(filer_name, apiversion[0], apiversion[1])
     out = conn.set_transport_type(transport_type)
     check_zapi_error(out, "connection to filer failed: %s")
     out = conn.set_style("LOGIN")
     check_zapi_error(out, "connection to filer failed: %s")
     out = conn.set_admin_user(user, password)
     check_zapi_error(out, "connection to filer failed: %s")
     self.conn = conn
Beispiel #6
0
def netapp_connect(cluster, user, pw):
    """Initialise NetApp cluster connection and return connection object"""
    conn = NaServer(cluster, 1, 3)
    response = conn.set_style('LOGIN')
    if (response and response.results_errno() != 0):
        resp = response.results_reason()
        print ('Unable to set authentication style %s' % resp)
        sys.exit(2)

    conn.set_admin_user(user, pw)
    response = conn.set_transport_type('HTTP')
    if (response and response.results_errno() != 0):
        resp = response.results_reason()
        print ('Unable to set HTTP transport %s' % resp)
        sys.exit(2)

    return conn
class Filer:
    """A NetApp filer."""
    def __init__(self, hostname, user, passwd):
        self.api = NaServer(hostname, 1, 3)
        self.api.set_style('LOGIN')
        self.api.set_admin_user(user, passwd)
        self.api.set_transport_type('HTTPS')

        self.name = hostname
        out = self.invoke('system-get-version')
        self.version = out.child_get_string('version')

        # Used for caching performance object descriptions:
        self.perf_obj_info = {}

    def create_volume(self, name, aggr, size):
        v = FlexVol(self, name)
        v.create(aggr, size)
        return v

    def flexshare_disable(self):
        """Equivalent to 'priority off' on the CLI."""

        self.invoke('priority-disable')

    def flexshare_enable(self):
        """Equivalent to 'priority on' on the CLI."""

        self.invoke('priority-enable')

    def flexshare_is_enabled(self):
        """Return boolean representing whether FlexShare is enabled."""

        out = self.invoke('priority-list-info')

        if out.child_get_string('status') == 'on':
            return True
        else:
            return False

    def get_cifs_homedirs(self):
        """
        Equivalent to 'cifs homedir' on the CLI.

        Return an array of cifs home directory paths.
        """

        out = self.invoke('cifs-homedir-paths-get')

        if out.has_children():
            homedirs = []
            for d in out.child_get('homedir-paths').children_get():
                homedirs.append(d.element['content'])
            return homedirs
        else:
            return []

    def get_export(self, export_path):
        """
        Return an Export object representing NFS share at export_path.

        If export does not exist, return False.
        """

        if self.has_export(export_path):
            return (Export(self, export_path))
        else:
            return False

    def get_exports(self):
        """Return a list of Export objects of filer's configured NFS shares."""

        out = self.invoke('nfs-exportfs-list-rules')

        exports = []

        for export in out.child_get('rules').children_get():
            path = export.child_get_string('pathname')
            exports.append(Export(self, path))

        return exports

    def get_fs_status_msg(self):
        """Return a string containing the file system status message."""

        return self.get_oid('.1.3.6.1.4.1.789.1.5.7.2.0')

    def get_oid(self, oid):
        """Return a generic OID from the NetApp SNMP MIB."""

        out = self.invoke('snmp-get', 'object-id', oid)
        return out.child_get_string('value')

    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 get_perf_object_info(self, objectname):
        """
        Return dict of static information about perf counter 'objectname'.

        Information is returned as a dict of dicts.
        """

        # Check cache:
        if self.perf_obj_info.has_key(objectname):
            return self.perf_obj_info[objectname]

        out = self.invoke('perf-object-counter-list-info', 'objectname',
                          objectname)
        counters = {}
        for counter in out.child_get('counters').children_get():
            name = counter.child_get_string('name')
            counters[name] = {}
            counters[name]['desc'] = counter.child_get_string('desc')
            counters[name]['privilege-level'] = counter.child_get_string(
                'privilege-level')

            ## Handle optional keys:
            for opt_key in ('base-counter', 'properties', 'type', 'unit'):
                opt_val = counter.child_get_string(opt_key)
                if opt_val:
                    counters[name][opt_key] = opt_val
                elif opt_key == 'type':
                    counters[name]['type'] = 'scalar'

            labels = counter.child_get('labels')
            if labels:
                counters[name]['labels'] = labels.child_get_string(
                    'label-info').split(',')

        # Store info in cache and return
        self.perf_obj_info[objectname] = counters
        return counters

    def get_perf_object_list(self):
        """Return dict of filer performance object names and privileges."""

        out = self.invoke('perf-object-list-info')
        objs = {}
        for obj in out.child_get('objects').children_get():
            objs[obj.child_get_string('name')] = obj.child_get_string(
                'privilege-level')
        return objs

    def get_root_name(self):
        """Return a string containing the Filer's root volume's name."""

        out = self.invoke('aggr-get-root-name')
        return out.child_get_string('root-volume')

    def get_share(self, name):
        """
        Return a Share object representing the existing CIFS share of name.

        If share does not exist, return False.
        """

        if self.has_share(name):
            return (Share(self, name))
        else:
            return False

    def get_shares(self):
        """Return a list of Share objects containing filer's CIFS exports."""

        out = self.invoke_cli('cifs', 'shares')

        # Pattern of output is two header lines, followed by each share name
        # starting at the left-hand side of the output.  Regexp accounts
        # For share name being able to include whitespace and other
        # characters - match is anchored on first "/" following whitespace,
        # which is presumed to be the start of the mount point.

        output = out.child_get('cli-output').element['content'].splitlines()

        share_pattern = re.compile(r'^([a-zA-Z].*\S)\s+\/')

        shares = []

        for line in output[2:]:
            m = share_pattern.match(line)
            if m:
                shares.append(Share(self, m.groups()[0]))

        return shares

    def get_option(self, name):
        """Equivalent to 'options <name>' on the CLI."""

        out = self.invoke('options-get', 'name', name)
        return out.child_get_string('value')

    def get_volume(self, name):
        """Return FlexVol object of existing vol 'name'; else return False."""

        if self.has_volume(name):
            return (FlexVol(self, name))
        else:
            return False

    def get_volumes(self):
        """Retun a list of FlexVol objects that exist on filer."""

        volumes = []

        out = self.invoke('volume-list-info')
        for volume in out.child_get('volumes').children_get():
            name = volume.child_get_string('name')
            volumes.append(FlexVol(self, name))

        return volumes

    def has_export(self, path):
        """Check if filer has NFS export name; return boolean."""

        export = Export(self, path)
        return export.configured()

    def has_share(self, name):
        """Check if filer has CIFS share name; return boolean."""

        share = Share(self, name)
        return share.configured()

    def has_volume(self, name):
        """Check if filer has FlexVol name; return boolean."""

        try:
            self.invoke('volume-list-info', 'volume', name)
        except OntapApiException as e:
            if e.errno == '13040':
                return False
            else:
                raise
        return True

    def invoke(self, *args):
        out = self.api.invoke(*args)
        if out.results_status() == 'failed':
            raise OntapApiException(out.results_errno(), 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 invoke_elem(self, naelement):
        """Call the NetApp API using an NaElement."""

        out = self.api.invoke_elem(naelement)
        if out.results_status() == 'failed':
            raise OntapApiException(out.results_errno(), out.results_reason())
        return out

    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 set_option(self, option, value):
        """Equivalent to 'options <option> <value>' on the CLI."""

        self.invoke('options-set', 'name', option, 'value', value)

    def _xmltree_to_dict(self, out, int_values=(), key='name', value='value'):
        """Convert thinly-veiled XML from ONTAP API to a dict."""
        options = {}

        for option in out.child_get('options').children_get():
            name = option.child_get_string(key)
            if name in int_values:
                options[name] = option.child_get_int(value)
            else:
                options[name] = option.child_get_string(value)

        return options

    def _xmltree_to_list(self, nae, outer_name, inner_name):
        """
        Return list converted from ONTAP API NaElement 'nae'.

        nae - NaElement from ONTAP API
        outer_name - outer 'child' of NaElement
        inner_name - inner 'child' of NaElement

        """

        out_list = []
        if nae.child_get(outer_name):
            for item in nae.child_get(outer_name).children_get():
                inner_val = item.child_get_string(inner_name)
                if inner_val is not None:
                    out_list.append(inner_val)

        return out_list
Beispiel #8
0
class Filer:
    """A NetApp filer."""

    def __init__(self, hostname, user, passwd):
        self.api = NaServer(hostname, 1, 3)
        self.api.set_style('LOGIN')
        self.api.set_admin_user(user, passwd)
        self.api.set_transport_type('HTTPS')

        self.name = hostname
        out = self.invoke('system-get-version')
        self.version = out.child_get_string('version')

        # Used for caching performance object descriptions:
        self.perf_obj_info = {}

    def create_volume(self, name, aggr, size):
        v = FlexVol(self, name)
        v.create(aggr, size)
        return v

    def flexshare_disable(self):
        """Equivalent to 'priority off' on the CLI."""

        self.invoke('priority-disable')

    def flexshare_enable(self):
        """Equivalent to 'priority on' on the CLI."""

        self.invoke('priority-enable')

    def flexshare_is_enabled(self):
        """Return boolean representing whether FlexShare is enabled."""

        out = self.invoke('priority-list-info')

        if out.child_get_string('status') == 'on':
            return True
        else:
            return False

    def get_cifs_homedirs(self):
        """
        Equivalent to 'cifs homedir' on the CLI.

        Return an array of cifs home directory paths.
        """

        out = self.invoke('cifs-homedir-paths-get')

        if out.has_children():
            homedirs = []
            for d in out.child_get('homedir-paths').children_get():
                homedirs.append(d.element['content'])
            return homedirs
        else:
            return []

    def get_export(self, export_path):
        """
        Return an Export object representing NFS share at export_path.

        If export does not exist, return False.
        """

        if self.has_export(export_path):
            return(Export(self, export_path))
        else:
            return False

    def get_exports(self):
        """Return a list of Export objects of filer's configured NFS shares."""

        out = self.invoke('nfs-exportfs-list-rules')

        exports = []

        for export in out.child_get('rules').children_get():
            path = export.child_get_string('pathname')
            exports.append(Export(self, path))

        return exports                         

    def get_fs_status_msg(self):
        """Return a string containing the file system status message."""

        return self.get_oid('.1.3.6.1.4.1.789.1.5.7.2.0')

    def get_oid(self, oid):
        """Return a generic OID from the NetApp SNMP MIB."""

        out = self.invoke('snmp-get', 'object-id', oid)
        return out.child_get_string('value')

    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 get_perf_object_info(self, objectname):
        """
        Return dict of static information about perf counter 'objectname'.

        Information is returned as a dict of dicts.
        """

        # Check cache:
        if self.perf_obj_info.has_key(objectname):
            return self.perf_obj_info[objectname]
        
        out = self.invoke('perf-object-counter-list-info',
                          'objectname', objectname)
        counters = {}
        for counter in out.child_get('counters').children_get():
            name = counter.child_get_string('name')
            counters[name] = {}
            counters[name]['desc'] = counter.child_get_string('desc')
            counters[name]['privilege-level'] = counter.child_get_string(
                'privilege-level')

            ## Handle optional keys:
            for opt_key in ('base-counter', 'properties', 'type', 'unit'):
                opt_val = counter.child_get_string(opt_key)
                if opt_val:
                    counters[name][opt_key] = opt_val
                elif opt_key == 'type':
                    counters[name]['type'] = 'scalar'

            labels = counter.child_get('labels')
            if labels:
                counters[name]['labels'] = labels.child_get_string(
                    'label-info').split(',')

        # Store info in cache and return
        self.perf_obj_info[objectname] = counters
        return counters

    def get_perf_object_list(self):
        """Return dict of filer performance object names and privileges."""

        out = self.invoke('perf-object-list-info')
        objs = {}
        for obj in out.child_get('objects').children_get():
            objs[obj.child_get_string('name')] = obj.child_get_string(
                'privilege-level')
        return objs

    def get_root_name(self):
        """Return a string containing the Filer's root volume's name."""

        out = self.invoke('aggr-get-root-name')
        return out.child_get_string('root-volume')

    def get_share(self, name):
        """
        Return a Share object representing the existing CIFS share of name.

        If share does not exist, return False.
        """

        if self.has_share(name):
            return(Share(self, name))
        else:
            return False   
    
    def get_shares(self):
        """Return a list of Share objects containing filer's CIFS exports."""

        out = self.invoke_cli('cifs', 'shares')

        # Pattern of output is two header lines, followed by each share name
        # starting at the left-hand side of the output.  Regexp accounts
        # For share name being able to include whitespace and other
        # characters - match is anchored on first "/" following whitespace,
        # which is presumed to be the start of the mount point.

        output = out.child_get('cli-output').element['content'].splitlines()

        share_pattern = re.compile(r'^([a-zA-Z].*\S)\s+\/')

        shares = []
        
        for line in output[2:]:
            m = share_pattern.match(line)
            if m:
                shares.append(Share(self, m.groups()[0]))

        return shares

    def get_option(self, name):
        """Equivalent to 'options <name>' on the CLI."""

        out = self.invoke('options-get', 'name', name)
        return out.child_get_string('value')

    def get_volume(self, name):
        """Return FlexVol object of existing vol 'name'; else return False."""

        if self.has_volume(name):
            return(FlexVol(self, name))
        else:
            return False

    def get_volumes(self):
        """Retun a list of FlexVol objects that exist on filer."""

        volumes = []

        out = self.invoke('volume-list-info')
        for volume in out.child_get('volumes').children_get():
            name = volume.child_get_string('name')
            volumes.append(FlexVol(self, name))

        return volumes

    def has_export(self, path):
        """Check if filer has NFS export name; return boolean."""

        export = Export(self, path)
        return export.configured()

    def has_share(self, name):
        """Check if filer has CIFS share name; return boolean."""

        share = Share(self, name)
        return share.configured()

    def has_volume(self, name):
        """Check if filer has FlexVol name; return boolean."""
        
        try:
            self.invoke('volume-list-info', 'volume', name)
        except OntapApiException as e:
            if e.errno == '13040':
                return False
            else:
                raise
        return True

    def invoke(self, *args):
        out = self.api.invoke(*args)
        if out.results_status() == 'failed':
            raise OntapApiException(out.results_errno(), 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 invoke_elem(self, naelement):
        """Call the NetApp API using an NaElement."""

        out = self.api.invoke_elem(naelement)
        if out.results_status() == 'failed':
            raise OntapApiException(out.results_errno(), out.results_reason())
        return out

    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 set_option(self, option, value):
        """Equivalent to 'options <option> <value>' on the CLI."""

        self.invoke('options-set', 'name', option, 'value', value)

    def _xmltree_to_dict(self, out, int_values=(), key='name', value='value'):
        """Convert thinly-veiled XML from ONTAP API to a dict."""
        options = {}

        for option in out.child_get('options').children_get():
            name = option.child_get_string(key)
            if name in int_values:
                options[name] = option.child_get_int(value)
            else:
                options[name] = option.child_get_string(value)

        return options

    def _xmltree_to_list(self, nae, outer_name, inner_name):
        """
        Return list converted from ONTAP API NaElement 'nae'.

        nae - NaElement from ONTAP API
        outer_name - outer 'child' of NaElement
        inner_name - inner 'child' of NaElement

        """

        out_list = []
        if nae.child_get(outer_name):
            for item in nae.child_get(outer_name).children_get():
                inner_val = item.child_get_string(inner_name)
                if inner_val is not None:
                    out_list.append(inner_val)

        return out_list