class ZTP(host_service.HostModule):
    """DBus endpoint that executes ZTP related commands
    """
    @staticmethod
    def _run_command(commands):
        """Run a ZTP command"""
        cmd = ['/usr/bin/ztp']
        if isinstance(commands, list):
            cmd.extend(commands)
        else:
            cmd.append(commands)

        try:
            rc = 0
            output = subprocess.check_output(cmd)
        except subprocess.CalledProcessError as err:
            rc = err.returncode
            output = ""

        return rc, output

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='',
                         out_signature='')
    def enable(self):
        self._run_command("enable")

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='',
                         out_signature='s')
    def getcfg(self):
        ztp_cfg = ZTPCfg()
        ad = getCfg('admin-mode', ztp_cfg=ztp_cfg)
        if ad == False:
            return "disabled"
        else:
            return "enabled"

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='',
                         out_signature='')
    def disable(self):
        self._run_command(["disable", "-y"])

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='',
                         out_signature='s')
    def status(self):
        print("Calling ZTP Status")
        b = ztp_status()
        print("Returning", b)
        return b
示例#2
0
class IMAGE_MGMT(host_service.HostModule):
    """DBus endpoint that executes CFG_MGMT related commands """
    @staticmethod
    def _run_command(options):
        """ Run config mgmt command """
        cmd = ['/usr/bin/sonic_installer']
        for x in options:
            cmd.append(str(x))

        output = ""
        try:
            print("cmd", cmd)
            rc = 0
            output = subprocess.check_output(cmd)
            print('Output -> ', output)

        except subprocess.CalledProcessError as err:
            print("Exception when calling get_sonic_error -> %s\n" % (err))
            rc = err.returncode
            output = err.output

        return rc, output

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='as',
                         out_signature='is')
    def action(self, options):
        return IMAAGE_MGMT._run_command(options)
class Showtech(host_service.HostModule):
    """DBus endpoint that executes the "show techsupport" command
    """
    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='s',
                         out_signature='is')
    def info(self, date):
        print("Host side: Running show techsupport")
        cmd = ['/usr/bin/generate_dump']
        if date:
            cmd.append("-s")
            cmd.append(date)

        try:
            rc = 0
            output = subprocess.check_output(cmd)
        except subprocess.CalledProcessError as err:
            rc = err.returncode
            output = ""
            print("Host side: Failed", rc)
            return rc, output
        output_string = output.decode("utf-8")
        output_file_match = re.search('\/var\/.*dump.*\.gz', output_string)
        if output_file_match is not None:
            output_filename = output_file_match.group()
        else:
            output_filename = ""
        return rc, output_filename
class CFG_MGMT(host_service.HostModule):
    """DBus endpoint that executes CFG_MGMT related commands """
    @staticmethod
    def _run_command(commands, options):
        """ Run config mgmt command """
        cmd = ['/usr/bin/config']
        if isinstance(commands, list):
            cmd.extend(commands)
        else:
            cmd.append(commands)

        for x in options:
            cmd.append(str(x))
        output = ""
        try:
            print("cmd", cmd)
            rc = 0
            output = subprocess.check_output(cmd)
            print('Output -> ', output)

        except subprocess.CalledProcessError as err:
            print("Exception when calling get_sonic_error -> %s\n" % (err))
            rc = err.returncode
            output = err.output

        return rc, output

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='as',
                         out_signature='is')
    def save(self, options):
        return CFG_MGMT._run_command(["save", "-y"], options)

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='as',
                         out_signature='is')
    def reload(self, options):
        return CFG_MGMT._run_command(["reload", "-y"], options)

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='as',
                         out_signature='is')
    def load(self, options):
        return CFG_MGMT._run_command(["load", "-y"], options)
示例#5
0
class Showtech(host_service.HostModule):
    """DBus endpoint that executes the "show techsupport" command
    """
    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='s',
                         out_signature='is')
    def info(self, date):

        ERROR_TAR_FAILED = 5
        ERROR_PROCFS_SAVE_FAILED = 6
        ERROR_INVALID_ARGUMENT = 10

        err_dict = {
            ERROR_INVALID_ARGUMENT: 'Invalid input: Incorrect DateTime format',
            ERROR_TAR_FAILED:
            'Failure saving information into compressed output file',
            ERROR_PROCFS_SAVE_FAILED: 'Saving of process information failed'
        }

        cmd = ['/usr/local/bin/generate_dump']
        if date:
            cmd.append("-s")
            cmd.append(date)

        try:
            result = subprocess.run(cmd,
                                    capture_output=True,
                                    text=True,
                                    check=True)

        except subprocess.CalledProcessError as err:
            errmsg = err_dict.get(err.returncode)

            if errmsg is None:
                output = 'Error: Failure code {:-5}'.format(err.returncode)
            else:
                output = errmsg

            print("%Error: Host side: Failed: " + str(err.returncode))
            return err.returncode, output

        output_file_match = re.search('\/var\/.*dump.*\.gz', result.stdout)
        output_filename = output_file_match.group()
        return result.returncode, output_filename
示例#6
0
class FETCH_ENVIRONMENT(host_service.HostModule):
    """DBus endpoint that executes CFG_MGMT related commands """
    @staticmethod
    def _run_command(options):
        """ Run show environment command """
        cmd = ['/usr/bin/show', 'environment']

        output = ""
        try:
            rc = 0
            output = subprocess.check_output(cmd)
            print('Output -> ', output)

        except subprocess.CalledProcessError as err:
            print("Exception when calling get_sonic_error -> %s\n" % (err))
            rc = err.returncode
            output = err.output
        return rc, output

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='as',
                         out_signature='is')
    def action(self, options):
        return FETCH_ENVIRONMENT._run_command(options)
示例#7
0
class CFG_MGMT(host_service.HostModule):
    """DBus endpoint that executes CFG_MGMT related commands """
    @staticmethod
    def _run_command(commands, options):
        """ Run config mgmt command """
        cmd = ['/usr/bin/config']
        if isinstance(commands, list):
            cmd.extend(commands)
        else:
            cmd.append(commands)

        cmd.extend(str(x) for x in options)
        output = ""
        try:
            print("cmd", cmd)
            rc = 0
            output = subprocess.check_output(cmd)
            print('Output -> ', output)

        except subprocess.CalledProcessError as err:
            print("Exception when calling get_sonic_error -> %s\n" % (err))
            rc = err.returncode
            output = err.output

        return rc, output

    @staticmethod
    def _docker_copy(container, _file, tempdir, copy_to_container):
        # Copy files/folders to/from containers
        if copy_to_container:
            src = os.path.join(tempdir, container, _file.lstrip('/'))
            dst = container + ':' + _file
        else:
            src = container + ':' + _file
            dst = os.path.join(tempdir, container, _file.lstrip('/'))
            try:
                os.makedirs(os.path.dirname(dst), exist_ok=True)
            except OSError:
                pass

        cmd = ['/usr/bin/docker', 'cp', '-aL', src, dst]
        try:
            rc = 0
            subprocess.check_call(cmd)
        except subprocess.CalledProcessError as err:
            rc = err.returncode

        return rc

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='as',
                         out_signature='is')
    def save(self, options):
        """Save configuration"""
        tempdir = tempfile.mkdtemp()
        try:
            config = self._load_config()
            for module, modcfg in config.items():
                destdir = os.path.join(tempdir, module)
                os.mkdir(destdir)

                container = modcfg.get('container', None)
                if container is None:
                    # Copy from host
                    for _file in modcfg.get('files', []):
                        # Copy individual files
                        src = _file
                        dst = os.path.join(destdir,
                                           os.path.dirname(_file.lstrip('/')))
                        try:
                            os.makedirs(dst, exist_ok=True)
                        except OSError:
                            # dir already exists
                            pass
                        shutil.copy(src, dst)

                    for folder in modcfg.get('folders', []):
                        # Copy directory trees
                        src = folder
                        dst = os.path.join(destdir, folder.lstrip('/'))
                        shutil.copytree(src, dst, symlinks=True)

                else:
                    # Copy from container
                    for _file in modcfg.get('files', []):
                        self._docker_copy(container, _file, tempdir, False)
                    for folder in modcfg.get('folders', []):
                        self._docker_copy(container, folder, tempdir, False)

            tfile = os.path.join(tempdir, 'config_db.json')
            rc, output = CFG_MGMT._run_command(["save", "-y"], [tfile])
            if rc != 0:
                return rc, output

            # Copy config_db.json to /etc/sonic
            shutil.copy(tfile, '/etc/sonic')

            if options:
                filename = options[0]
            else:
                filename = DEFAULT_FILE

            with tarfile.open(filename, 'w') as tf:
                tf.add(tempdir, arcname='.')

        finally:
            shutil.rmtree(tempdir, ignore_errors=True)

        return 0, filename

    def _load_from_tar(self, load_type, options):
        if options:
            filename = options[0]
        else:
            filename = DEFAULT_FILE

        tempdir = tempfile.mkdtemp()
        try:
            with tarfile.open(filename, 'r') as tf:
                tf.extractall(tempdir)

            config = self._load_config()
            for module, modcfg in config.items():
                container = modcfg.get('container', None)
                srcdir = os.path.join(tempdir, module)
                if container is None:
                    # Copy from host
                    for _file in modcfg.get('files', []):
                        # Copy individual files
                        src = os.path.join(srcdir, _file.lstrip('/'))
                        dst = os.path.dirname(_file)
                        try:
                            os.makedirs(dst, exist_ok=True)
                        except OSError:
                            # dir already exists
                            pass
                        shutil.copy(src, dst)

                    for folder in modcfg.get('folders', []):
                        # Copy directory trees
                        src = os.path.join(srcdir, folder.lstrip('/'))
                        dst = folder
                        try:
                            # We have to shell out to /bin/cp, since copytree
                            # will abort if the destination already exists
                            cmd = ['/bin/cp', '-a', src, dst]
                            subprocess.check_call(cmd)
                        except subprocess.CalledProcessError as err:
                            pass
                else:
                    # Copy to container
                    for _file in modcfg.get('files', []):
                        self._docker_copy(container, _file, tempdir, True)
                    for folder in modcfg.get('folders', []):
                        self._docker_copy(container, folder, tempdir, True)

            config_db_json = os.path.join(tempdir, 'config_db.json')
            rc, output = CFG_MGMT._run_command([load_type, "-y"],
                                               [config_db_json])
        except (tarfile.ReadError, FileNotFoundError):
            # Either file is not found or file is not a tarfile
            # If options is not given, the default file will be
            # /etc/sonic/sonic_config.tar. This file will not exist in
            # older releases, so on upgrade to newer releases, we will need
            # to fallback to the old `config load` command which will pull
            # from /etc/sonic/config_db.json. If options is given, then
            # try to read it as a tarfile, if that fails, then treat is as
            # a config_db.json dump.
            rc, output = CFG_MGMT._run_command([load_type, "-y"], options)
        finally:
            shutil.rmtree(tempdir, ignore_errors=True)

        return rc, output

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='as',
                         out_signature='is')
    def reload(self, options):
        """Reload configuration and restart services"""
        return self._load_from_tar('reload', options)

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='as',
                         out_signature='is')
    def load(self, options):
        """Load configuration"""
        return self._load_from_tar('load', options)

    @staticmethod
    def _get_version():
        '''Return the SONiC version string, or NONE if command to retrieve it fails'''
        try:
            proc = subprocess.Popen(
                "sonic-cfggen -y /etc/sonic/sonic_version.yml -v build_version",
                shell=True,
                stdout=subprocess.PIPE)
            out, err = proc.communicate()
            build_version_info = out.strip()
            return build_version_info.decode("utf-8")
        except subprocess.CalledProcessError:
            return None

    @staticmethod
    def _create_host_file(fname, content=None):
        '''Create a file under /host'''
        version = CFG_MGMT._get_version()
        if version:
            filename = '/host/image-' + version + "/" + fname
            try:
                f = open(filename, "w+")
                if content:
                    f.write(content)
                f.close()
                return 0, ""
            except IOError as e:
                return 1, ("Unable to create file [%s] - %s" % (filename, e))
        else:
            return 1, "Unable to get SONiC version: operation not performed"

    @staticmethod
    def _delete_host_file(fname):
        '''Delete a file under /host'''
        version = CFG_MGMT._get_version()
        if version:
            filename = '/host/image-' + version + "/" + fname
            if not os.path.exists(filename):
                return 1, "No configuration erase operation to cancel."
            try:
                os.remove(filename)
                return 0, ""
            except IOError as e:
                return 1, ("Unable to delete file [%s] - %s" % (filename, e))
        else:
            return 1, "Unable to get SONiC version: operation not performed"

    @staticmethod
    def _run_command_erase(option):
        """ Run config mgmt command """
        rc = 1
        if option == "":
            rc, err = CFG_MGMT._create_host_file("/pending_erase")
        elif option == "boot":
            rc, err = CFG_MGMT._create_host_file("/pending_erase", "boot")
        elif option == "install":
            rc, err = CFG_MGMT._create_host_file("/pending_erase", "install")
        elif option == "no":
            rc, err = CFG_MGMT._delete_host_file("/pending_erase")
        return rc, err

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='s',
                         out_signature='is')
    def write_erase(self, option):
        return self._run_command_erase(option)

    @staticmethod
    def _load_config():
        """Load configuration for save/load/reload"""
        config = {}
        if os.path.exists(CFG_FILE):
            with open(CFG_FILE, 'r') as cfg:
                config = json.load(cfg)

        return config
示例#8
0
class Kdump(host_service.HostModule):
    """DBus endpoint that executes the kdump provided command
    """
    @staticmethod
    def _run_command(cmd):
        '''!
        Execute a given command

        @param cmd (str) Command to execute. Since we execute the command directly, and not within the
                         context of the shell, the full path needs to be provided ($PATH is not used).
                         Command parameters are simply separated by a space.
                         Should be either string or a list

        '''
        try:
            shcmd = shlex.split(cmd)
            proc = subprocess.Popen(shcmd,
                                    shell=False,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE,
                                    bufsize=1,
                                    close_fds=True)
            output_stdout, output_stderr = proc.communicate()
            list_stdout = []
            for l in output_stdout.splitlines():
                list_stdout.append(str(l.decode()))
            list_stderr = []
            for l in output_stderr.splitlines():
                list_stderr.append(str(l.decode()))
            return (proc.returncode, list_stdout, list_stderr)
        except (OSError, ValueError) as e:
            print(
                "!Exception [%s] encountered while processing the command : %s"
                % (str(e), str(cmd)))
            return (1, None, None)

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='bis',
                         out_signature='is')
    def command(self, enabled, num_dumps, memory):

        if memory != '':
            cmd = '/usr/bin/config kdump memory %s' % memory
        elif num_dumps != 0:
            cmd = '/usr/bin/config kdump num_dumps %d' % num_dumps
        else:
            if enabled:
                cmd = '/usr/bin/config kdump enable'
            else:
                cmd = '/usr/bin/config kdump disable'
        (rc, output, output_err) = self._run_command(cmd)

        result = ''
        for s in output:
            if s != '':
                s = '\n' + s
            result = result + s

        return 0, result

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='s',
                         out_signature='is')
    def state(self, param):

        # All results, formatted as a  string
        if param != None:
            cmd = '/usr/bin/show kdump %s' % param
        else:
            cmd = '/usr/bin/show kdump'
        (rc, output, output_err) = self._run_command(cmd)
        result = ''
        for s in output:
            if s != '':
                s = '\n' + s
            result = result + s

        return 0, result
示例#9
0
class ZTP(host_service.HostModule):
    """DBus endpoint that executes ZTP related commands
    """
    @staticmethod
    def _run_command(commands):
        """Run a ZTP command"""
        cmd = ['/usr/bin/ztp']
        if isinstance(commands, list):
            cmd.extend(commands)
        else:
            cmd.append(commands)

        try:
            rc = 0
            output = subprocess.check_output(cmd)
        except subprocess.CalledProcessError as err:
            rc = err.returncode
            output = ""

        return rc, output

    @staticmethod
    def _run_command_run():
        """Run a ZTP command"""
        cmd = '/usr/bin/ztp run -y'

        output = ""
        try:
            rc = 0
            proc = subprocess.Popen(cmd,
                                    shell=True,
                                    stdout=subprocess.PIPE,
                                    stderr=None)
            (out, err) = proc.communicate()
            out = out.decode()
            rc = proc.returncode
            if rc == 0:
                output = out.rstrip('\n')
            else:
                if isinstance(out, list):
                    out[0] = out[0].rstrip('\n')
                rc = 0
                output = out
        except subprocess.CalledProcessError as err:
            rc = 1

        output = out.rstrip('\n')
        return rc, output

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='',
                         out_signature='')
    def enable(self):
        self._run_command("enable")

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='',
                         out_signature='s')
    def getcfg(self):
        ztp_cfg = ZTPCfg()
        ad = getCfg('admin-mode', ztp_cfg=ztp_cfg)
        if ad == False:
            return "disabled"
        else:
            return "enabled"

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='',
                         out_signature='')
    def disable(self):
        self._run_command(["disable", "-y"])

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='',
                         out_signature='s')
    def status(self):
        print("Calling ZTP Status")
        b = ztp_status()
        print("Returning", b)
        return b

    @host_service.method(host_service.bus_name(MOD_NAME),
                         in_signature='',
                         out_signature='is')
    def run(self):
        rc, output = self._run_command_run()
        return rc, output