Example #1
0
 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 __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 = {}
Example #3
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
Example #4
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
Example #5
0
    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 = {}
Example #6
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 cluster_setup(cluster):
    print("> " + cluster["cluster-name"] + ": Creating Cluster ")

    for node in cluster["cluster-nodes"]:

        print("---> " + node["node-name"] + ": Working on node ")
        # Building Session - REST
        s = requests.Session()
        s.url = "https://{}".format(node["ip"])
        s.verify = False
        s.auth = (node["user"], node["password"])
        s.headers = {
            "Content-Type": "application/hal+json",
            "Accept": "application/hal+json"
        }

        # Building Session - ZAPI
        session = NaServer(node["ip"], 1, 140)
        session.set_server_type("Filer")
        session.set_admin_user(node["user"], node["password"])
        session.set_transport_type("HTTPS")

        # STEP: Create cluster
        if ("-01" in node["node-name"]):
            print("---> " + node["node-name"] + ": Creating cluster...")

            # create cluster API
            api = "/api/cluster"

            # creating body
            body = {
                "contact": cluster["contact"],
                "location": cluster["location"],
                "name": cluster["cluster-name"],
                "password": cluster["password"],
                "management_interface": {}
            }
            # add cluster mgmt
            for lif in cluster["net-interfaces"]:
                if (lif["role"] == "cluster-mgmt"):
                    body["management_interface"]["ip"] = {
                        "address": lif["address"],
                        "netmask": lif["netmask"]
                    }
                    for route in cluster["net-routes"]:
                        if (route["destination"] == "0.0.0.0/0"):
                            body["management_interface"]["ip"][
                                "gateway"] = route["gateway"]
                            break
                        else:
                            continue
                    break
                else:
                    continue
            # add ntp server
            #if (cluster.get("ntp-servers")):
            #        for ntp_server in cluster["ntp-servers"]:
            #                body["ntp_servers"].append(ntp_server["server-name"])
            # add licenses
            #for ontap_license in cluster["licenses"]:
            #       body["licenses"].append(cluster["licenses"][ontap_license])

            response = s.post(url=s.url + api, data=json.dumps(body))
            print("URL==" + s.url + api)  #debug
            print("BODY==" + json.dumps(body))  #debug
            if response:
                print(response.json())
            else:
                print("WE DIDNT GET RESPONSE")
                #sys.exit()
            status = handle_job(s, response)
            if (status == "success"):
                print("---> " + node["node-name"] + ": SUCCESS")
            else:
                print("---> " + node["node-name"] + ": " + status)
                sys.exit()

        # STEP: Reading cluster LIF IP for joining additional nodes later
        if ("-01" in node["node-name"]):
            print(
                "--- " + node["node-name"] +
                ": Reading cluster LIF IP for joining further nodes later...")
            api = NaElement("net-interface-modify")
            for lif in cluster["net-interfaces"]:
                if (lif["role"] == "cluster-mgmt"):
                    api.child_add_string("home-port", lif["home-port"])
                    api.child_add_string("interface-name", "cluster_mgmt")
                    api.child_add_string("vserver", cluster["cluster-name"])
                else:
                    continue
            xo = session.invoke_elem(api)
            if (xo.results_status() == "failed"):
                print("Error:\n")
                print(xo.sprintf())
                sys.exit(1)
            print("Received:\n")
            print(xo.sprintf())
            api1 = NaElement("net-interface-revert")
            api1.child_add_string("interface-name", "cluster_mgmt")
            api1.child_add_string("vserver", cluster["cluster-name"])
            xo1 = session.invoke_elem(api1)
            if (xo1.results_status() == "failed"):
                print("Error:\n")
                print(xo1.sprintf())
                sys.exit(1)
            print("Received:\n")
            print(xo1.sprintf())
            api = "/api/network/ip/interfaces"
            url_params = "?fields=services,ip.address&services=cluster_core&max_records=1"
            response = s.get(url=s.url + api + url_params)
            status = handle_job(s, response)
            if (status == "success"):
                clus_lif_ip = response.json()["records"][0]["ip"]["address"]
                print("---> " + node["node-name"] + ": SUCCESS")
            else:
                print("---> " + node["node-name"] + ": " + status)
                sys.exit(1)

        # STEP: Join nodes to cluster
        if (not "-01" in node["node-name"]):
            print("--- " + node["node-name"] + ": Joining node to cluster...")
            zapi_post = NaElement("cluster-join")
            zapi_post.child_add_string("cluster-ip-address", clus_lif_ip)
            zapi_post_return = session.invoke_elem(zapi_post)
            if (zapi_post_return.results_status() == "failed"):
                print("---> " + node["node-name"] + ": " +
                      zapi_post_return.sprintf().strip())
                sys.exit(1)
            else:
                zapi_get = NaElement("cluster-create-join-progress-get")
                is_complete = ""
                join_iterator = 1
                while is_complete != "true" and \
                                join_iterator < 13:
                    time.sleep(10)
                    zapi_get_return = session.invoke_elem(zapi_get)
                    is_complete = zapi_get_return.child_get(
                        "attributes").child_get(
                            "cluster-create-join-progress-info"
                        ).child_get_string("is-complete")
                    action_status = zapi_get_return.child_get(
                        "attributes").child_get(
                            "cluster-create-join-progress-info"
                        ).child_get_string("status")
                    join_iterator = join_iterator + 1
                if (is_complete == "true") and (action_status == "success"):
                    print("---> " + node["node-name"] + ": SUCCESS")
                else:
                    print("---> " + node["node-name"] + ": " +
                          zapi_get.sprintf().strip())
                    print("---> " + node["node-name"] + ": " +
                          zapi_get_return.sprintf().strip())
                    sys.exit(1)
Example #8
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
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
Example #11
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
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