Exemple #1
0
 def proc_run(self, command, stdin_str="", timeout=10, outputfun=None):
     # Timeout is only used with outputfun
     self.debug("run '" + str(" ".join(command)) + "', input len=" +
                str(len(stdin_str)))
     try:
         if outputfun:
             return self.proc_run_outputfun(command, timeout, outputfun)
         else:
             proc = subprocess.Popen(command,
                                     stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     universal_newlines=True)
             (stdoutdata, stderrdata) = proc.communicate(input=stdin_str)
             self.debug("run finished, output len=" + str(len(stdoutdata)) +
                        ", err len=" + str(len(stderrdata)))
             return (stdoutdata, stderrdata)
     except OSError as oserr:
         if oserr.errno == 2:  # File not found
             raise ActionError({
                 'error':
                 "Dependent application not found, please install: " +
                 str(command[0])
             })
         raise ActionError(
             {'error': "OSError when executing " + str(command[0])})
     except:
         self.debug("run failed:\n" +
                    repr(traceback.format_exception(*sys.exc_info())))
         raise ActionError(
             {'error': "Failed to execute " + str(command[0])})
Exemple #2
0
    def get_conn_details(self):
        def safe_ncs_decrypt(value):
            if value is None:
                return None
            try:
                return _ncs.decrypt(len=255, ciphertext=value)
            except:
                return _ncs.decrypt(ciphertext=value)

        with single_trans(_ncs.READ_WRITE) as t:
            device_path = '/ncs:devices/device{"' + self.dev_name + '"}'
            address = str(t.get_elem(device_path + '/address'))
            device_type_netconf = t.exists(device_path +
                                           '/device-type/netconf')
            try:
                port = int(t.get_elem(device_path + '/port'))
            except:
                port = 830
            self.debug("Device addr={0}, port={1}, netconf={2}".format(
                address, port, device_type_netconf))
            if device_type_netconf != True:
                raise ActionError(
                    {'error': "pioneer only works with NETCONF devices"})

            authgroup_name = str(t.get_elem(device_path + '/authgroup'))
            ## FIXME default-map only, add umap support -- or at least an error message
            authgroup_path = '/ncs:devices/authgroups/group{"' + authgroup_name + '"}/default-map'

            missing = []
            try:
                remote_name = str(t.get_elem(authgroup_path + '/remote-name'))
            except:
                missing.append('remote-name')
            try:
                remote_password = str(
                    t.get_elem(authgroup_path +
                               '/remote-password'))  # FIXME password only
            except:
                missing.append('remote-password')

            if len(missing) > 0:
                raise ActionError({
                    'error':
                    'required configuration in authentication group {0} default-map missing: {1}'
                    .format(authgroup_name, ', '.join(missing))
                })

            self.debug("Credentials user={0}, pass={1}".format(
                remote_name, remote_password))
            remote_password = safe_ncs_decrypt(remote_password)

            return (address, port, remote_name, remote_password)
Exemple #3
0
    def _yang_sftp_read_settings(self):
        def safe_get(sock, th, path, default=None):
            try:
                return maapi.get_elem(sock, th, path)
            except _ncs.error.Error as e:
                if e.confd_errno == _ncs.ERR_NOEXISTS:
                    if isinstance(default, Exception):
                        raise default
                    return default
                else:
                    raise e

        sock = socket.socket()
        maapi.connect(sock, '127.0.0.1', _ncs.PORT)
        try:
            maapi.start_user_session2(sock, 'admin', 'system', [], '127.0.0.1',
                                      0, _ncs.PROTO_TCP)
            try:
                th = maapi.start_trans(sock, _ncs.RUNNING, _ncs.READ)

                sftp_prefix = '/{0}:{1}/{2}/'.format(ns.ns.prefix,
                                                     ns.ns.pioneer_pioneer_,
                                                     ns.ns.pioneer_sftp_)
                host_path = sftp_prefix + ns.ns.pioneer_host_
                host = safe_get(
                    sock, th, host_path,
                    ActionError({'error': host_path + ' is required'}))
                port = safe_get(sock, th, sftp_prefix + ns.ns.pioneer_port_,
                                22)
                username_path = sftp_prefix + ns.ns.pioneer_username_
                username = safe_get(
                    sock, th, username_path,
                    ActionError({'error': username_path + ' is required'}))
                password = safe_get(sock, th,
                                    sftp_prefix + ns.ns.pioneer_password_,
                                    None)

                rsa_key_path = safe_get(
                    sock, th, sftp_prefix + ns.ns.pioneer_rsa_key_path_,
                    '~/id_rsa')

                return (str(host), int(port), str(username),
                        password and str(password)
                        or None, os.path.expanduser(str(rsa_key_path)))
            finally:
                maapi.end_user_session(sock)
        finally:
            sock.close()
Exemple #4
0
    def cb_action(self, uinfo, op_name, kp, params):
        self.debug("========== pioneer cb_action() ==========")

        dev_name = str(kp[-3][0])
        self.debug("thandle={0} usid={1}".format(uinfo.actx_thandle,
                                                 uinfo.usid))

        try:
            if op_name.tag not in self.handlers:
                raise ActionError({
                    'error':
                    "Operation not implemented: {0}".format(op_name)
                })

            handler_cls = self.handlers[op_name.tag]
            handler = handler_cls(self.msocket, uinfo, dev_name, params,
                                  self.debug)
            result = handler.perform()
            return self.action_response(uinfo, result)

        ##----------------------------------------------------------------
        except ActionError as ae:
            self.debug("ActionError exception")
            return self.action_response(uinfo, ae.get_info())
        except:
            self.debug("Other exception: " +
                       repr(traceback.format_exception(*sys.exc_info())))
            msg = "Operation failed"
            dp.action_reply_values(
                uinfo, [TV(XT(ns.ns.hash, ns.ns.pioneer_error), V(msg))])
            return _ncs.CONFD_OK
Exemple #5
0
    def fetch_model_list_netconf_monitoring(self, method):
        if method == 'subtree':
            self.debug(
                "Fetching YANG model list with netconf-console --get --subtree from netconf-monitoring"
            )
            xml_get_result = self.nc_perform(
                subtree=
                "<netconf-state xmlns='urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring'/>"
            )
        else:
            self.debug(
                "Fetching YANG model list with netconf-console --get --xpath from netconf-monitoring"
            )
            xml_get_result = self.nc_perform(xpath="/netconf-state")

        self.debug("Parsing model names")
        (model_list_txt, stderr) = self.proc_run([
            self.get_exe_path("xsltproc"), "--nonet", "--novalid",
            self.pkg_root_dir + "/load-dir/ncs-extract-schemas.xsl", "-"
        ], xml_get_result)
        self.debug("Parsed:\n" + model_list_txt + "\n" + stderr)
        if stderr != "":
            raise ActionError(
                {'error': "Failed to parse model list:\n" + stderr})
        model_list = []
        lines = [line for line in model_list_txt.split("\n") if line != ""]
        for line in lines:
            tokens = line.split(":")
            self.debug("tokens=" + str(tokens))
            if tokens[0] == 'netconf':
                model_list += [tokens[1]]
            else:
                model_list += [tokens[0]]
        return model_list
Exemple #6
0
    def nc_perform(self,
                   op='get',
                   subtree='',
                   xpath='',
                   method_opts=None,
                   timeout=20):
        if subtree != '':
            method_opts = ["--subtree", subtree]
        elif xpath != '':
            method_opts = ["--xpath", xpath]
        elif method_opts is None:
            method_opts = []

        (address, port, remote_name, remote_password) = self.get_conn_details()
        args = ["--" + op] + method_opts + [
            "--host=" + str(address), "--port=" + str(port),
            "--user="******"--password="******"Calling netconf_console %s" % args)
        netconf_console.main(args, iocb, self)
        self.debug("Returned from netconf_console")

        xml_get_result = iocb.out.getvalue().decode()
        stderr = iocb.err.getvalue().decode()

        self.debug("Fetched:\n" + xml_get_result + "\n\n" + stderr)
        if stderr != "":
            raise ActionError(
                {'error': "Failed to execute " + op + ":\n" + stderr})
        return xml_get_result
Exemple #7
0
    def transition_to_state(self, to_state_filename):
        filename = os.path.join(self.states_dir, to_state_filename)
        if not os.path.exists(filename):
            state_name = self.state_filename_to_name(to_state_filename,
                                                     self.dev_name)
            raise ActionError(
                {'error': 'No such state: {0}'.format(state_name)})

        try:
            self.debug("Transition_to_state: #{0}\n".format(filename))
            self.extend_timeout(
                120
            )  # Max 120 seconds for executing the transaction and a compare-config
            thandle = maapi.start_trans2(self.msocket, _ncs.RUNNING,
                                         _ncs.READ_WRITE, self.uinfo.usid)
            maapi.delete(self.msocket, thandle,
                         "/ncs:devices/device{" + self.dev_name + "}/config")
            maapi.load_config(self.msocket, thandle,
                              maapi.CONFIG_J + maapi.CONFIG_MERGE, filename)
            maapi.apply_trans(self.msocket, thandle, False)
            self.debug("Committed\n")
            result = maapi.request_action(
                self.msocket, [], 0,
                "/ncs:devices/device{" + self.dev_name + "}/compare-config")
            if [] == result:
                self.debug("In sync\n")
                return True
            else:
                return "out-of-sync"
        except:
            self.debug("Exception: " +
                       repr(traceback.format_exception(*sys.exc_info())))
            return "transaction-failed"
        finally:
            maapi.finish_trans(self.msocket, thandle)
Exemple #8
0
 def create_yang_dir(self):
     try:
         os.makedirs(self.yang_directory)
     except:
         pass
     if not os.path.exists(self.yang_directory):
         raise ActionError({
             'error':
             'Failed to create directory {0}'.format(self.yang_directory)
         })
Exemple #9
0
    def get_exe_path(self, exe):
        path = self.get_exe_path_from_PATH(exe)
        if not os.path.exists(path):
            raise ActionError({
                'error':
                'Unable to execute {0}, command no found in PATH {1}'.format(
                    exe, os.environ['PATH'])
            })

        return path
Exemple #10
0
 def extract_capas_from_hello(self, hello_str):
     self.debug("Parsing capas")
     (capas_list_txt, stderr) = self.proc_run([
         self.get_exe_path("xsltproc"), "--nonet", "--novalid",
         self.pkg_root_dir + "/load-dir/ncs-extract-capas.xsl", "-"
     ], hello_str)
     self.debug("Parsed:\n" + capas_list_txt + "\n" + stderr)
     if stderr != "":
         raise ActionError(
             {'error': "Failed to parse capas list:\n" + stderr})
     capas_list = capas_list_txt.split("\n")
     return capas_list
Exemple #11
0
    def perform(self):
        self.debug("yang_sftp() with device {0}".format(self.dev_name))
        self.create_yang_dir()

        try:
            import paramiko
        except ImportError:
            raise ActionError(
                {'error': "SFTP support requires paramiko to be available"})

        host, port, username, password, rsa_key_path = self._yang_sftp_read_settings(
        )

        model_list = self.parse_name_list(self.name)
        match = lambda n: (len(model_list) == 0) or (n in model_list)

        self.debug('connecting to {0}:{1} as {2}...'.format(
            host, port, username))
        message = 'connection failed'
        try:
            with paramiko.Transport((host, port)) as transport:
                if password is None:
                    pkey = paramiko.RSAKey.from_private_key_file(rsa_key_path)
                    transport.connect(username=username, pkey=pkey)
                else:
                    transport.connect(username=username, password=password)

                with paramiko.SFTPClient.from_transport(transport) as sftp:
                    names = [
                        name for name in sftp.listdir(self.remote_path)
                        if name.endswith('.yang') and match(name)
                    ]
                    self.progress_msg(
                        "Downloading {0} files using SFTP...\n".format(
                            len(names)))
                    for name in names:
                        remote_path = '{0}/{1}'.format(self.remote_path, name)
                        local_path = os.path.join(self.yang_directory, name)
                        sftp.get(remote_path, local_path)
                    message = 'transferred {0} files'.format(len(names))
        except Exception as e:
            message = 'error occured {0}'.format(e)
            self.debug(message)
            self.debug(traceback.format_exc())

        return {'yang-directory': self.yang_directory, 'message': message}
Exemple #12
0
 def abort(self, msg):
     raise ActionError({'error': msg})