Example #1
0
def remove(module, details=False):
    '''
    Attempt to remove a Perl module that was installed from CPAN. Because the
    ``cpan`` command doesn't actually support "uninstall"-like functionality,
    this function will attempt to do what it can, with what it has from CPAN.

    Until this function is declared stable, USE AT YOUR OWN RISK!

    CLI Example:

    .. code-block:: bash

        salt '*' cpan.remove Old::Package
    '''
    ret = {
        'old': None,
        'new': None,
    }

    info = show(module)
    if 'error' in info:
        return {'error': info['error']}

    version = info.get('installed version', None)
    if version is None:
        return ret

    ret['old'] = version

    if 'cpan build dirs' not in info:
        return {'error': 'No CPAN data available to use for uninstalling'}

    mod_pathfile = module.replace('::', '/') + '.pm'
    ins_path = info['installed file'].replace(mod_pathfile, '')

    files = []
    for build_dir in info['cpan build dirs']:
        contents = os.listdir(build_dir)
        if 'MANIFEST' not in contents:
            continue
        mfile = os.path.join(build_dir, 'MANIFEST')
        with salt.utils.files.fopen(mfile, 'r') as fh_:
            for line in fh_.readlines():
                if line.startswith('lib/'):
                    files.append(line.replace('lib/', ins_path).strip())

    rm_details = {}
    for file_ in files:
        if file_ in rm_details:
            continue
        log.trace('Removing {0}'.format(file_))
        if __salt__['file.remove'](file_):
            rm_details[file_] = 'removed'
        else:
            rm_details[file_] = 'unable to remove'

    if details:
        ret['details'] = rm_details

    return ret
Example #2
0
    def _get_all_files(self, path, *exclude):
        """
        Walk implementation. Version in python 2.x and 3.x works differently.
        """
        files = list()
        dirs = list()
        links = list()

        if os.access(path, os.R_OK):
            for obj in os.listdir(path):
                obj = os.path.join(path, obj)
                valid = True
                for ex_obj in exclude:
                    if obj.startswith(str(ex_obj)):
                        valid = False
                        continue
                if not valid or not os.path.exists(obj) or not os.access(obj, os.R_OK):
                    continue
                if salt.utils.path.islink(obj):
                    links.append(obj)
                elif os.path.isdir(obj):
                    dirs.append(obj)
                    f_obj, d_obj, l_obj = self._get_all_files(obj, *exclude)
                    files.extend(f_obj)
                    dirs.extend(d_obj)
                    links.extend(l_obj)
                elif os.path.isfile(obj):
                    files.append(obj)

        return sorted(files), sorted(dirs), sorted(links)
Example #3
0
def _trim_files(files, trim_output):
    # Trim the file list for output
    count = 100
    if not isinstance(trim_output, bool):
        count = trim_output

    if not(isinstance(trim_output, bool) and trim_output is False) and len(files) > count:
        files = files[:count]
        files.append("List trimmed after {0} files.".format(count))

    return files
Example #4
0
def _trim_files(files, trim_output):
    '''
    Trim the file list for output.
    '''
    count = 100
    if not isinstance(trim_output, bool):
        count = trim_output

    if not(isinstance(trim_output, bool) and trim_output is False) and len(files) > count:
        files = files[:count]
        files.append("List trimmed after {0} files.".format(count))

    return files
Example #5
0
def file_list(*packages):
    '''
    List the files that belong to a package. Not specifying any packages will
    return a list of _every_ file on the system's package database (not
    generally recommended).

    CLI Examples:

    .. code-block:: bash

        salt '*' lowpkg.file_list httpd
        salt '*' lowpkg.file_list httpd postfix
        salt '*' lowpkg.file_list
    '''
    errors = []
    ret = set([])
    pkgs = {}
    cmd = 'dpkg -l {0}'.format(' '.join(packages))
    out = __salt__['cmd.run_all'](cmd, python_shell=False)
    if out['retcode'] != 0:
        msg = 'Error:  ' + out['stderr']
        log.error(msg)
        return msg
    out = out['stdout']

    for line in out.splitlines():
        if line.startswith('ii '):
            comps = line.split()
            pkgs[comps[1]] = {
                'version': comps[2],
                'description': ' '.join(comps[3:])
            }
        if 'No packages found' in line:
            errors.append(line)
    for pkg in pkgs:
        files = []
        cmd = 'dpkg -L {0}'.format(pkg)
        for line in __salt__['cmd.run'](cmd, python_shell=False).splitlines():
            files.append(line)
        fileset = set(files)
        ret = ret.union(fileset)
    return {'errors': errors, 'files': list(ret)}
Example #6
0
    def _list_zip(name, cached):
        '''
        List the contents of a zip archive.
        Password-protected ZIP archives can still be listed by zipfile, so
        there is no reason to invoke the unzip command.
        '''
        dirs = set()
        files = []
        links = []
        try:
            with contextlib.closing(zipfile.ZipFile(cached)) as zip_archive:
                for member in zip_archive.infolist():
                    path = member.filename
                    if salt.utils.platform.is_windows():
                        if path.endswith('/'):
                            # zipfile.ZipInfo objects on windows use forward
                            # slash at end of the directory name.
                            dirs.add(path)
                        else:
                            files.append(path)
                    else:
                        mode = member.external_attr >> 16
                        if stat.S_ISLNK(mode):
                            links.append(path)
                        elif stat.S_ISDIR(mode):
                            dirs.add(path)
                        else:
                            files.append(path)

                _files = copy.deepcopy(files)
                for path in _files:
                    # ZIP files created on Windows do not add entries
                    # to the archive for directories. So, we'll need to
                    # manually add them.
                    dirname = ''.join(path.rpartition('/')[:2])
                    if dirname:
                        dirs.add(dirname)
                        if dirname in files:
                            files.remove(dirname)
            return list(dirs), files, links
        except zipfile.BadZipfile:
            raise CommandExecutionError('{0} is not a ZIP file'.format(name))
Example #7
0
File: opkg.py Project: zxstar/salt
def file_dict(*packages, **kwargs):  # pylint: disable=unused-argument
    """
    List the files that belong to a package, grouped by package. Not
    specifying any packages will return a list of _every_ file on the system's
    package database (not generally recommended).

    CLI Examples:

    .. code-block:: bash

        salt '*' pkg.file_list httpd
        salt '*' pkg.file_list httpd postfix
        salt '*' pkg.file_list
    """
    errors = []
    ret = {}
    cmd_files = ["opkg", "files"]

    if not packages:
        packages = list(list_pkgs().keys())

    for package in packages:
        files = []
        cmd = cmd_files[:]
        cmd.append(package)
        out = __salt__["cmd.run_all"](cmd,
                                      output_loglevel="trace",
                                      python_shell=False)
        for line in out["stdout"].splitlines():
            if line.startswith("/"):
                files.append(line)
            elif line.startswith(" * "):
                errors.append(line[3:])
                break
            else:
                continue
        if files:
            ret[package] = files

    return {"errors": errors, "packages": ret}
Example #8
0
def file_dict(*packages):
    '''
    List the files that belong to a package, grouped by package. Not
    specifying any packages will return a list of _every_ file on the system's
    package database (not generally recommended).

    CLI Examples:

    .. code-block:: bash

        salt '*' pkg.file_list httpd
        salt '*' pkg.file_list httpd postfix
        salt '*' pkg.file_list
    '''
    errors = []
    ret = {}
    cmd_files = ['opkg', 'files']

    if not packages:
        packages = list(list_pkgs().keys())

    for package in packages:
        files = []
        cmd = cmd_files[:]
        cmd.append(package)
        out = __salt__['cmd.run_all'](cmd,
                                      output_loglevel='trace',
                                      python_shell=False)
        for line in out['stdout'].splitlines():
            if line.startswith('/'):
                files.append(line)
            elif line.startswith(' * '):
                errors.append(line[3:])
                break
            else:
                continue
        if files:
            ret[package] = files

    return {'errors': errors, 'packages': ret}
Example #9
0
def file_list(*packages):
    """
    List the files that belong to a package. Not specifying any packages will
    return a list of _every_ file on the system's package database (not
    generally recommended).

    CLI Examples:

    .. code-block:: bash

        salt '*' lowpkg.file_list httpd
        salt '*' lowpkg.file_list httpd postfix
        salt '*' lowpkg.file_list
    """
    errors = []
    ret = set([])
    pkgs = {}
    cmd = "dpkg -l {0}".format(" ".join(packages))
    out = __salt__["cmd.run_all"](cmd, python_shell=False)
    if out["retcode"] != 0:
        msg = "Error:  " + out["stderr"]
        log.error(msg)
        return msg
    out = out["stdout"]

    for line in out.splitlines():
        if line.startswith("ii "):
            comps = line.split()
            pkgs[comps[1]] = {"version": comps[2], "description": " ".join(comps[3:])}
        if "No packages found" in line:
            errors.append(line)
    for pkg in pkgs:
        files = []
        cmd = "dpkg -L {0}".format(pkg)
        for line in __salt__["cmd.run"](cmd, python_shell=False).splitlines():
            files.append(line)
        fileset = set(files)
        ret = ret.union(fileset)
    return {"errors": errors, "files": list(ret)}
Example #10
0
 def _list_rar(name, cached):
     '''
     List the contents of a rar archive.
     '''
     dirs = []
     files = []
     if HAS_RARFILE:
         with rarfile.RarFile(cached) as rf:
             for member in rf.infolist():
                 path = member.filename.replace('\\', '/')
                 if member.isdir():
                     dirs.append(path + '/')
                 else:
                     files.append(path)
     else:
         if not salt.utils.which('rar'):
             raise CommandExecutionError(
                 'rar command not available, is it installed?'
             )
         output = __salt__['cmd.run'](
             ['rar', 'lt', name],
             python_shell=False,
             ignore_retcode=False)
         matches = re.findall(r'Name:\s*([^\n]+)\s*Type:\s*([^\n]+)', output)
         for path, type_ in matches:
             if type_ == 'Directory':
                 dirs.append(path + '/')
             else:
                 files.append(path)
         if not dirs and not files:
             raise CommandExecutionError(
                 'Failed to list {0}, is it a rar file? If so, the '
                 'installed version of rar may be too old to list data in '
                 'a parsable format. Installing the rarfile Python module '
                 'may be an easier workaround if newer rar is not readily '
                 'available.'.format(name),
                 info={'error': output}
             )
     return dirs, files, []
Example #11
0
 def _list_rar(name, cached):
     """
     List the contents of a rar archive.
     """
     dirs = []
     files = []
     if HAS_RARFILE:
         with rarfile.RarFile(cached) as rf:
             for member in rf.infolist():
                 path = member.filename.replace("\\", "/")
                 if member.isdir():
                     dirs.append(path + "/")
                 else:
                     files.append(path)
     else:
         if not salt.utils.path.which("rar"):
             raise CommandExecutionError(
                 "rar command not available, is it installed?"
             )
         output = __salt__["cmd.run"](
             ["rar", "lt", name], python_shell=False, ignore_retcode=False
         )
         matches = re.findall(r"Name:\s*([^\n]+)\s*Type:\s*([^\n]+)", output)
         for path, type_ in matches:
             if type_ == "Directory":
                 dirs.append(path + "/")
             else:
                 files.append(path)
         if not dirs and not files:
             raise CommandExecutionError(
                 "Failed to list {}, is it a rar file? If so, the "
                 "installed version of rar may be too old to list data in "
                 "a parsable format. Installing the rarfile Python module "
                 "may be an easier workaround if newer rar is not readily "
                 "available.".format(name),
                 info={"error": output},
             )
     return dirs, files, []
Example #12
0
 def _list_zip(name, cached):
     '''
     List the contents of a zip archive.
     Password-protected ZIP archives can still be listed by zipfile, so
     there is no reason to invoke the unzip command.
     '''
     dirs = []
     files = []
     links = []
     try:
         with contextlib.closing(zipfile.ZipFile(cached)) as zip_archive:
             for member in zip_archive.infolist():
                 mode = member.external_attr >> 16
                 path = member.filename
                 if stat.S_ISLNK(mode):
                     links.append(path)
                 elif stat.S_ISDIR(mode):
                     dirs.append(path)
                 else:
                     files.append(path)
         return dirs, files, links
     except zipfile.BadZipfile:
         raise CommandExecutionError('{0} is not a ZIP file'.format(name))
Example #13
0
    def _list_tar(name, cached, decompress_cmd, failhard=False):
        """
        List the contents of a tar archive.
        """
        dirs = []
        files = []
        links = []
        try:
            open_kwargs = (
                {"name": cached}
                if not isinstance(cached, subprocess.Popen)
                else {"fileobj": cached.stdout, "mode": "r|"}
            )
            with contextlib.closing(tarfile.open(**open_kwargs)) as tar_archive:
                for member in tar_archive.getmembers():
                    _member = salt.utils.data.decode(member.name)
                    if member.issym():
                        links.append(_member)
                    elif member.isdir():
                        dirs.append(_member + "/")
                    else:
                        files.append(_member)
            return dirs, files, links

        except tarfile.ReadError:
            if failhard:
                if isinstance(cached, subprocess.Popen):
                    stderr = cached.communicate()[1]
                    if cached.returncode != 0:
                        raise CommandExecutionError(
                            "Failed to decompress {}".format(name),
                            info={"error": stderr},
                        )
            else:
                if not salt.utils.path.which("tar"):
                    raise CommandExecutionError("'tar' command not available")
                if decompress_cmd is not None and isinstance(decompress_cmd, str):
                    # Guard against shell injection
                    try:
                        decompress_cmd = [
                            shlex.quote(x) for x in shlex.split(decompress_cmd)
                        ]
                    except AttributeError:
                        raise CommandExecutionError("Invalid CLI options")
                else:
                    if (
                        salt.utils.path.which("xz")
                        and __salt__["cmd.retcode"](
                            ["xz", "-t", cached],
                            python_shell=False,
                            ignore_retcode=True,
                        )
                        == 0
                    ):
                        decompress_cmd = ["xz", "--decompress", "--stdout"]

                if decompress_cmd:
                    decompressed = subprocess.Popen(
                        decompress_cmd + [shlex.quote(cached)],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                    )
                    return _list_tar(name, decompressed, None, True)

        raise CommandExecutionError(
            "Unable to list contents of {}. If this is an XZ-compressed tar "
            "archive, install XZ Utils to enable listing its contents. If it "
            "is compressed using something other than XZ, it may be necessary "
            "to specify CLI options to decompress the archive. See the "
            "documentation for details.".format(name)
        )
Example #14
0
    def _list_tar(name, cached, decompress_cmd, failhard=False):
        '''
        List the contents of a tar archive.
        '''
        dirs = []
        files = []
        links = []
        try:
            open_kwargs = {'name': cached} \
                if not isinstance(cached, subprocess.Popen) \
                else {'fileobj': cached.stdout, 'mode': 'r|'}
            with contextlib.closing(
                    tarfile.open(**open_kwargs)) as tar_archive:
                for member in tar_archive.getmembers():
                    if member.issym():
                        links.append(member.name)
                    elif member.isdir():
                        dirs.append(member.name + '/')
                    else:
                        files.append(member.name)
            return dirs, files, links

        except tarfile.ReadError:
            if failhard:
                if isinstance(cached, subprocess.Popen):
                    stderr = cached.communicate()[1]
                    if cached.returncode != 0:
                        raise CommandExecutionError(
                            'Failed to decompress {0}'.format(name),
                            info={'error': stderr})
            else:
                if not salt.utils.path.which('tar'):
                    raise CommandExecutionError(
                        '\'tar\' command not available')
                if decompress_cmd is not None:
                    # Guard against shell injection
                    try:
                        decompress_cmd = ' '.join(
                            [_quote(x) for x in shlex.split(decompress_cmd)])
                    except AttributeError:
                        raise CommandExecutionError('Invalid CLI options')
                else:
                    if salt.utils.path.which('xz') \
                            and __salt__['cmd.retcode'](['xz', '-t', cached],
                                                        python_shell=False,
                                                        ignore_retcode=True) == 0:
                        decompress_cmd = 'xz --decompress --stdout'

                if decompress_cmd:
                    decompressed = subprocess.Popen('{0} {1}'.format(
                        decompress_cmd, _quote(cached)),
                                                    shell=True,
                                                    stdout=subprocess.PIPE,
                                                    stderr=subprocess.PIPE)
                    return _list_tar(name, decompressed, None, True)

        raise CommandExecutionError(
            'Unable to list contents of {0}. If this is an XZ-compressed tar '
            'archive, install XZ Utils to enable listing its contents. If it '
            'is compressed using something other than XZ, it may be necessary '
            'to specify CLI options to decompress the archive. See the '
            'documentation for details.'.format(name))
Example #15
0
def remove(module, details=False):
    """
    Attempt to remove a Perl module that was installed from CPAN. Because the
    ``cpan`` command doesn't actually support "uninstall"-like functionality,
    this function will attempt to do what it can, with what it has from CPAN.

    Until this function is declared stable, USE AT YOUR OWN RISK!

    CLI Example:

    .. code-block:: bash

        salt '*' cpan.remove Old::Package
    """
    ret = {
        "old": None,
        "new": None,
    }

    info = show(module)
    if "error" in info:
        return {"error": info["error"]}

    version = info.get("installed version", None)
    if version is None:
        return ret

    ret["old"] = version

    if "cpan build dirs" not in info:
        return {"error": "No CPAN data available to use for uninstalling"}

    mod_pathfile = module.replace("::", "/") + ".pm"
    ins_path = info["installed file"].replace(mod_pathfile, "")

    files = []
    for build_dir in info["cpan build dirs"]:
        contents = os.listdir(build_dir)
        if "MANIFEST" not in contents:
            continue
        mfile = os.path.join(build_dir, "MANIFEST")
        with salt.utils.files.fopen(mfile, "r") as fh_:
            for line in fh_.readlines():
                line = salt.utils.stringutils.to_unicode(line)
                if line.startswith("lib/"):
                    files.append(line.replace("lib/", ins_path).strip())

    rm_details = {}
    for file_ in files:
        if file_ in rm_details:
            continue
        log.trace("Removing {0}".format(file_))
        if __salt__["file.remove"](file_):
            rm_details[file_] = "removed"
        else:
            rm_details[file_] = "unable to remove"

    if details:
        ret["details"] = rm_details

    return ret
Example #16
0
    def _list_tar(name, cached, decompress_cmd, failhard=False):
        '''
        List the contents of a tar archive.
        '''
        dirs = []
        files = []
        links = []
        try:
            with contextlib.closing(tarfile.open(cached)) as tar_archive:
                for member in tar_archive.getmembers():
                    if member.issym():
                        links.append(member.name)
                    elif member.isdir():
                        dirs.append(member.name + '/')
                    else:
                        files.append(member.name)
            return dirs, files, links

        except tarfile.ReadError:
            if not failhard:
                if not salt.utils.which('tar'):
                    raise CommandExecutionError(
                        '\'tar\' command not available')
                if decompress_cmd is not None:
                    # Guard against shell injection
                    try:
                        decompress_cmd = ' '.join(
                            [_quote(x) for x in shlex.split(decompress_cmd)])
                    except AttributeError:
                        raise CommandExecutionError('Invalid CLI options')
                else:
                    if salt.utils.which('xz') \
                            and __salt__['cmd.retcode'](['xz', '-t', cached],
                                                        python_shell=False,
                                                        ignore_retcode=True) == 0:
                        decompress_cmd = 'xz --decompress --stdout'

                if decompress_cmd:
                    fd, decompressed = tempfile.mkstemp()
                    os.close(fd)
                    try:
                        cmd = '{0} {1} > {2}'.format(decompress_cmd,
                                                     _quote(cached),
                                                     _quote(decompressed))
                        result = __salt__['cmd.run_all'](cmd,
                                                         python_shell=True)
                        if result['retcode'] != 0:
                            raise CommandExecutionError(
                                'Failed to decompress {0}'.format(name),
                                info={'error': result['stderr']})
                        return _list_tar(name, decompressed, None, True)
                    finally:
                        try:
                            os.remove(decompressed)
                        except OSError as exc:
                            if exc.errno != errno.ENOENT:
                                log.warning(
                                    'Failed to remove intermediate '
                                    'decompressed archive %s: %s',
                                    decompressed, exc.__str__())

        raise CommandExecutionError(
            'Unable to list contents of {0}. If this is an XZ-compressed tar '
            'archive, install XZ Utils to enable listing its contents. If it '
            'is compressed using something other than XZ, it may be necessary '
            'to specify CLI options to decompress the archive. See the '
            'documentation for details.'.format(name))
Example #17
0
def remove(module, details=False, bin_env=None):
    '''
    Attempt to remove a Perl module that was installed from CPAN. Because the
    ``cpan`` command doesn't actually support 'uninstall'-like functionality,
    this function will attempt to do what it can, with what it has from CPAN.

    Until this function is declared stable, USE AT YOUR OWN RISK!

    CLI Example:

    .. code-block:: bash

        salt '*' cpan.remove Old::Package
    '''
    ret = {'error': None, 'old': None, 'new': None}

    info = show(module, bin_env=bin_env)
    ret['error'] = info.get('error', None)

    cpan_version = info.get('installed_version', None)
    if (cpan_version is None) or ('not installed' in cpan_version):
        log.debug(
            'Module "{}" already removed, no changes made'.format(module))
    else:
        mod_pathfile = module.replace('::', '/') + '.pm'
        ins_path = info['installed_file'].replace(mod_pathfile, '')

        rm_details = {}
        if 'cpan_build_dirs' in info:
            log.warning('No CPAN data available to use for uninstalling')

        files = []
        for build_dir in info['cpan_build_dirs']:
            # Check if the build directory exists, if not then skip
            if not os.path.isdir(build_dir):
                log.warning(
                    'Could not find CPAN build dir: {}'.format(build_dir))
                continue

            # If the manifest is moving then skip
            contents = os.listdir(build_dir)
            if 'MANIFEST' not in contents:
                continue

            mfile = os.path.join(build_dir, 'MANIFEST')
            with salt.utils.files.fopen(mfile, 'r') as fh_:
                for line in fh_.readlines():
                    line = salt.utils.stringutils.to_unicode(line)
                    if line.startswith('lib/'):
                        files.append(line.replace('lib/', ins_path).strip())

        for file_ in files:
            if file_ in rm_details:
                log.trace('Removing {}'.format(file_))
                continue
            if __salt__['file.remove'](file_):
                rm_details[file_] = 'removed'
            else:
                rm_details[file_] = 'unable to remove'

        new_info = show(module, bin_env=bin_env)

        if details:
            ret['details'] = rm_details

        # Only report changes, remove values that are the same before and after
        for k in info.copy().keys():
            if info.get(k) == new_info[k]:
                info.pop(k)
                new_info.pop(k, None)

        ret['old'] = info
        ret['new'] = new_info

    return ret