Пример #1
0
def _consolidate_repo_sources(sources):
    if not isinstance(sources, sourceslist.SourcesList):
        raise TypeError('"{0}" not a "{1}"'.format(type(sources),
                                                   sourceslist.SourcesList))

    consolidated = {}
    delete_files = set()
    base_file = sourceslist.SourceEntry('').file

    repos = filter(lambda s: not s.invalid, sources.list)

    for r in repos:
        key = str((getattr(r, 'architectures', []), r.disabled, r.type, r.uri))
        if key in consolidated:
            combined = consolidated[key]
            combined_comps = set(r.comps).union(set(combined.comps))
            consolidated[key].comps = list(combined_comps)
        else:
            consolidated[key] = sourceslist.SourceEntry(r.line)

        if r.file != base_file:
            delete_files.add(r.file)

    sources.list = consolidated.values()
    sources.save()
    for f in delete_files:
        try:
            os.remove(f)
        except:
            pass
    return sources
Пример #2
0
 def removeSelectedSources(self):
     for item in self.items:
         if item.checkState() == QtCore.Qt.Checked:
             self.model.removeRow(item.row())
             x = sourceslist.SourceEntry(str(item.text()))
             self.s.remove(x)
             self.s.save()
Пример #3
0
 def removeSelectedSources(self):
     for item in self.items:
         x = sourceslist.SourceEntry(str(item))
         self.s.remove(x)
         self.s.save()
     self.close()
     self.msg.exec_()
Пример #4
0
 def removeSelectedSources(self):
     for item in self.items:
         x = sourceslist.SourceEntry(str(item))
         self.s.remove(x)
         self.s.save()
     self.close()
     self.msg.setText("Your changes have been successfully applied")
     self.msg.exec_()
Пример #5
0
def expand_repo_def(repokwargs):
    '''
    Take a repository definition and expand it to the full pkg repository dict
    that can be used for comparison.  This is a helper function to make
    the Debian/Ubuntu apt sources sane for comparison in the pkgrepo states.

    There is no use to calling this function via the CLI.
    '''
    sanitized = {}

    if not apt_support:
        raise CommandExecutionError(
            'Error: aptsources.sourceslist python module not found'
        )

    repo = _strip_uri(repokwargs['repo'])

    if repo.startswith('ppa:') and __grains__['os'] == 'Ubuntu':
        dist = __grains__['lsb_distrib_codename']
        owner_name, ppa_name = repo[4:].split('/', 1)
        if 'ppa_auth' in repokwargs:
            auth_info = '{0}@'.format(repokwargs['ppa_auth'])
            repo = LP_PVT_SRC_FORMAT.format(auth_info, owner_name, ppa_name,
                                            dist)
        else:
            if ppa_format_support:
                repo = softwareproperties.ppa.expand_ppa_line(
                    repo, dist)[0]
            else:
                repo = LP_SRC_FORMAT.format(owner_name, ppa_name, dist)

        if file not in repokwargs:
            filename = '/etc/apt/sources.list.d/{0}-{1}-{2}.list'
            repokwargs['file'] = filename.format(owner_name, ppa_name,
                                                 dist)

    source_entry = sourceslist.SourceEntry(repo)
    for kwarg in _MODIFY_OK:
        if kwarg in repokwargs:
            setattr(source_entry, kwarg, repokwargs[kwarg])

    sanitized['file'] = source_entry.file
    sanitized['comps'] = getattr(source_entry, 'comps', [])
    sanitized['disabled'] = source_entry.disabled
    sanitized['dist'] = source_entry.dist
    sanitized['type'] = source_entry.type
    sanitized['uri'] = source_entry.uri.rstrip('/')
    sanitized['line'] = source_entry.line.strip()
    sanitized['architectures'] = getattr(source_entry, 'architectures', [])

    return sanitized
Пример #6
0
def mod_repo(repo, refresh=False, **kwargs):
    '''
    Modify one or more values for a repo.  If the repo does not exist, it will
    be created, so long as the definition is well formed.  For Ubuntu the
    "ppa:<project>/repo" format is acceptable. "ppa:" format can only be
    used to create a new repository.

    The following options are available to modify a repo definition::

        comps (a comma separated list of components for the repo, e.g. "main")
        file (a file name to be used)
        refresh (refresh the apt sources db when the mod is done)
        keyserver (keyserver to get gpg key from)
        keyid (key id to load with the keyserver argument)
        key_url (URl to a gpg key to add to the apt gpg keyring)
        consolidate (if true, will attempt to de-dup and consolidate sources)

    CLI Examples::

        salt '*' pkg.mod_repo 'myrepo definition' uri=http://new/uri
        salt '*' pkg.mod_repo 'myrepo definition' comps=main,universe
    '''
    if not apt_support:
        raise ImportError('Error: aptsources.sourceslist module not found')

    # to ensure no one sets some key values that _shouldn't_ be changed on the
    # object itself, this is just a white-list of "ok" to set properties
    _MODIFY_OK = set(
        ['uri', 'comps', 'architectures', 'disabled', 'file', 'dist'])
    if repo.startswith('ppa:') and __grains__['os'] == 'Ubuntu':
        if not ppa_format_support:
            error_str = 'cannot parse "ppa:" style repo definitions: {0}'
            raise Exception(error_str.format(repo))
        cmd = 'apt-add-repository -y {0}'.format(repo)
        out = __salt__['cmd.run_stdout'](cmd)
        if refresh is True or str(refresh).lower() == 'true':
            refresh_db()
        return {repo: out}
    else:
        sources = sourceslist.SourcesList()
        if kwargs.get('consolidate', False):
            # attempt to de-dup and consolidate all sources
            # down to entries in sources.list
            # this option makes it easier to keep the sources
            # list in a "sane" state.
            #
            # this should remove duplicates, consolidate comps
            # for a given source down to one line
            # and eliminate "invalid" and comment lines
            #
            # the second side effect is removal of files
            # that are not the main sources.list file
            sources = _consolidate_repo_sources(sources)

        repos = filter(lambda s: not s.invalid, sources)
        if repos:
            mod_source = None
            try:
                repo_type, repo_uri, repo_dist, repo_comps = _split_repo_str(
                    repo)
            except SyntaxError:
                error_str = 'Error: repo "{0}" not a well formatted definition'
                raise SyntaxError(error_str.format(repo))

            full_comp_list = set(repo_comps)

            if 'keyid' in kwargs:
                keyid = kwargs.pop('keyid', None)
                ks = kwargs.pop('keyserver', None)
                if not keyid or not ks:
                    error_str = 'both keyserver and keyid options required.'
                    raise NameError(error_str)
                cmd = 'apt-key export {0}'.format(keyid)
                output = __salt__['cmd.run_stdout'](cmd)
                imported = output.startswith('-----BEGIN PGP')
                if ks:
                    cmd = 'apt-key export {0}'.format(keyid)
                    output = __salt__['cmd.run_stdout'](cmd)
                    if not imported:
                        cmd = ('apt-key adv --keyserver {0} --logger-fd 1 '
                               '--recv-keys {1}')
                        out = __salt__['cmd.run_stdout'](cmd.format(ks, keyid))
                        if not out.find('imported') or out.find('not changed'):
                            error_str = 'Error: key retrieval failed: {0}'
                            raise Exception(
                                error_str.format(cmd.format(ks, keyid)))
            elif 'key_url' in kwargs:
                key_url = kwargs.pop('key_url', None)
                cmd = 'wget -q -O- {0} | apt-key add -'.format(key_url)
                out = __salt__['cmd.run_stdout'](cmd)
                if not out.upper().startswith('OK'):
                    error_str = 'Error: key retrieval failed: {0}'
                    raise Exception(error_str.format(cmd.format(key_url)))

            if 'comps' in kwargs:
                kwargs['comps'] = kwargs['comps'].split(',')
                full_comp_list.union(set(kwargs['comps']))
            else:
                kwargs['comps'] = list(full_comp_list)

            if 'architectures' in kwargs:
                kwargs['architectures'] = kwargs['architectures'].split(',')

            if 'disabled' in kwargs:
                kw_disabled = kwargs['disabled']
                if kw_disabled is True or str(kw_disabled).lower() == 'true':
                    kwargs['disabled'] = True
                else:
                    kwargs['disabled'] = False

            kw_type = kwargs.get('type')
            kw_dist = kwargs.get('dist')

            for source in repos:
                # This series of checks will identify the starting source line
                # and the resulting source line.  The idea here is to ensure
                # we are not retuning bogus data because the source line
                # has already been modified on a previous run.
                if ((source.type == repo_type and source.uri == repo_uri
                     and source.dist == repo_dist)
                        or (source.dist == kw_dist and source.type == kw_type
                            and source.type == kw_type)):

                    for comp in full_comp_list:
                        if comp in getattr(source, 'comps', []):
                            mod_source = source
                    if not source.comps:
                        mod_source = source
                    if mod_source:
                        break

            if not mod_source:
                mod_source = sourceslist.SourceEntry(repo)
                sources.list.append(mod_source)

            # if all comps aren't part of the disable
            # match, it is important we keep the comps
            # not destined to be disabled/enabled in
            # the original state
            if ('disabled' in kwargs
                    and mod_source.disabled != kwargs['disabled']):

                s_comps = set(mod_source.comps)
                r_comps = set(repo_comps)
                if s_comps.symmetric_difference(r_comps):
                    new_source = sourceslist.SourceEntry(source.line)
                    new_source.file = source.file
                    new_source.comps = list(r_comps.difference(s_comps))
                    source.comps = list(s_comps.difference(r_comps))
                    sources.insert(sources.index(source), new_source)
                    sources.save()

            for key in kwargs:
                if key in _MODIFY_OK and hasattr(mod_source, key):
                    if type(getattr(mod_source, key)) == type(kwargs[key]):
                        setattr(mod_source, key, kwargs[key])
            sources.save()
            if refresh is True or str(refresh).lower() == 'true':
                refresh_db()
            return {
                repo: {
                    'architectures': getattr(mod_source, 'architectures', []),
                    'comps': mod_source.comps,
                    'disabled': mod_source.disabled,
                    'file': mod_source.file,
                    'type': mod_source.type,
                    'uri': mod_source.uri,
                    'line': mod_source.line,
                }
            }
Пример #7
0
def _split_repo_str(repo):
    split = sourceslist.SourceEntry(repo)
    return split.type, split.uri, split.dist, split.comps
Пример #8
0
def mod_repo(repo, saltenv='base', **kwargs):
    '''
    Modify one or more values for a repo.  If the repo does not exist, it will
    be created, so long as the definition is well formed.  For Ubuntu the
    "ppa:<project>/repo" format is acceptable. "ppa:" format can only be
    used to create a new repository.

    The following options are available to modify a repo definition::

        comps (a comma separated list of components for the repo, e.g. "main")
        file (a file name to be used)
        keyserver (keyserver to get gpg key from)
        keyid (key id to load with the keyserver argument)
        key_url (URL to a gpg key to add to the apt gpg keyring)
        consolidate (if true, will attempt to de-dup and consolidate sources)

        * Note: Due to the way keys are stored for apt, there is a known issue
                where the key wont be updated unless another change is made
                at the same time.  Keys should be properly added on initial
                configuration.

    CLI Examples:

    .. code-block:: bash

        salt '*' pkg.mod_repo 'myrepo definition' uri=http://new/uri
        salt '*' pkg.mod_repo 'myrepo definition' comps=main,universe
    '''
    if not apt_support:
        raise ImportError('Error: aptsources.sourceslist module not found')

    # to ensure no one sets some key values that _shouldn't_ be changed on the
    # object itself, this is just a white-list of "ok" to set properties
    if repo.startswith('ppa:'):
        if __grains__['os'] == 'Ubuntu':
            # secure PPAs cannot be supported as of the time of this code
            # implementation via apt-add-repository.  The code path for
            # secure PPAs should be the same as urllib method
            if ppa_format_support and 'ppa_auth' not in kwargs:
                try:
                    get_repo(repo)
                    return {repo: ''}
                except Exception:
                    if float(__grains__['osrelease']) < 12.04:
                        cmd = 'apt-add-repository {0}'.format(repo)
                    else:
                        cmd = 'apt-add-repository -y {0}'.format(repo)
                    out = __salt__['cmd.run_stdout'](cmd, **kwargs)
                    # explicit refresh when a repo is modified.
                    refresh_db()
                    return {repo: out}
            else:
                if not ppa_format_support:
                    _warn_software_properties(repo)
                else:
                    log.info('Falling back to urllib method for private PPA')

                # fall back to urllib style
                try:
                    owner_name, ppa_name = repo[4:].split('/', 1)
                except ValueError:
                    raise CommandExecutionError(
                        'Unable to get PPA info from argument. '
                        'Expected format "<PPA_OWNER>/<PPA_NAME>" '
                        '(e.g. saltstack/salt) not found.  Received '
                        '{0!r} instead.'.format(repo[4:]))
                dist = __grains__['lsb_distrib_codename']
                # ppa has a lot of implicit arguments. Make them explicit.
                # These will defer to any user-defined variants
                kwargs['dist'] = dist
                ppa_auth = ''
                if file not in kwargs:
                    filename = '/etc/apt/sources.list.d/{0}-{1}-{2}.list'
                    kwargs['file'] = filename.format(owner_name, ppa_name,
                                                     dist)
                try:
                    launchpad_ppa_info = _get_ppa_info_from_launchpad(
                        owner_name, ppa_name)
                    if 'ppa_auth' not in kwargs:
                        kwargs['keyid'] = launchpad_ppa_info[
                            'signing_key_fingerprint']
                    else:
                        if 'keyid' not in kwargs:
                            error_str = 'Private PPAs require a ' \
                                        'keyid to be specified: {0}/{1}'
                            raise CommandExecutionError(
                                error_str.format(owner_name, ppa_name))
                except urllib2.HTTPError as exc:
                    raise CommandExecutionError(
                        'Launchpad does not know about {0}/{1}: {2}'.format(
                            owner_name, ppa_name, exc))
                except IndexError as e:
                    raise CommandExecutionError(
                        'Launchpad knows about {0}/{1} but did not '
                        'return a fingerprint. Please set keyid '
                        'manually: {2}'.format(owner_name, ppa_name, e))

                if 'keyserver' not in kwargs:
                    kwargs['keyserver'] = 'keyserver.ubuntu.com'
                if 'ppa_auth' in kwargs:
                    if not launchpad_ppa_info['private']:
                        raise CommandExecutionError(
                            'PPA is not private but auth credentials '
                            'passed: {0}'.format(repo))
                # assign the new repo format to the "repo" variable
                # so we can fall through to the "normal" mechanism
                # here.
                if 'ppa_auth' in kwargs:
                    ppa_auth = '{0}@'.format(kwargs['ppa_auth'])
                    repo = LP_PVT_SRC_FORMAT.format(ppa_auth, owner_name,
                                                    ppa_name, dist)
                else:
                    repo = LP_SRC_FORMAT.format(owner_name, ppa_name, dist)
        else:
            raise CommandExecutionError(
                'cannot parse "ppa:" style repo definitions: {0}'.format(repo))

    sources = sourceslist.SourcesList()
    if kwargs.get('consolidate', False):
        # attempt to de-dup and consolidate all sources
        # down to entries in sources.list
        # this option makes it easier to keep the sources
        # list in a "sane" state.
        #
        # this should remove duplicates, consolidate comps
        # for a given source down to one line
        # and eliminate "invalid" and comment lines
        #
        # the second side effect is removal of files
        # that are not the main sources.list file
        sources = _consolidate_repo_sources(sources)

    repos = filter(lambda s: not s.invalid, sources)
    mod_source = None
    try:
        repo_type, repo_uri, repo_dist, repo_comps = _split_repo_str(repo)
    except SyntaxError:
        raise SyntaxError(
            'Error: repo {0!r} not a well formatted definition'.format(repo))

    full_comp_list = set(repo_comps)

    if 'keyid' in kwargs:
        keyid = kwargs.pop('keyid', None)
        ks = kwargs.pop('keyserver', None)
        if not keyid or not ks:
            error_str = 'both keyserver and keyid options required.'
            raise NameError(error_str)
        cmd = 'apt-key export {0}'.format(keyid)
        output = __salt__['cmd.run_stdout'](cmd, **kwargs)
        imported = output.startswith('-----BEGIN PGP')
        if ks:
            if not imported:
                cmd = ('apt-key adv --keyserver {0} --logger-fd 1 '
                       '--recv-keys {1}')
                ret = __salt__['cmd.run_all'](cmd.format(ks, keyid), **kwargs)
                if ret['retcode'] != 0:
                    raise CommandExecutionError(
                        'Error: key retrieval failed: {0}'.format(
                            ret['stdout']))

    elif 'key_url' in kwargs:
        key_url = kwargs['key_url']
        fn_ = __salt__['cp.cache_file'](key_url, saltenv)
        cmd = 'apt-key add {0}'.format(fn_)
        out = __salt__['cmd.run_stdout'](cmd, **kwargs)
        if not out.upper().startswith('OK'):
            raise CommandExecutionError(
                'Error: key retrieval failed: {0}'.format(cmd.format(key_url)))

    if 'comps' in kwargs:
        kwargs['comps'] = kwargs['comps'].split(',')
        full_comp_list.union(set(kwargs['comps']))
    else:
        kwargs['comps'] = list(full_comp_list)

    if 'architectures' in kwargs:
        kwargs['architectures'] = kwargs['architectures'].split(',')

    if 'disabled' in kwargs:
        kw_disabled = kwargs['disabled']
        if kw_disabled is True or str(kw_disabled).lower() == 'true':
            kwargs['disabled'] = True
        else:
            kwargs['disabled'] = False

    kw_type = kwargs.get('type')
    kw_dist = kwargs.get('dist')

    for source in repos:
        # This series of checks will identify the starting source line
        # and the resulting source line.  The idea here is to ensure
        # we are not retuning bogus data because the source line
        # has already been modified on a previous run.
        if ((source.type == repo_type and source.uri == repo_uri
             and source.dist == repo_dist)
                or (source.dist == kw_dist and source.type == kw_type
                    and source.type == kw_type)):

            for comp in full_comp_list:
                if comp in getattr(source, 'comps', []):
                    mod_source = source
            if not source.comps:
                mod_source = source
            if mod_source:
                break

    if not mod_source:
        mod_source = sourceslist.SourceEntry(repo)
        sources.list.append(mod_source)

    # if all comps aren't part of the disable
    # match, it is important we keep the comps
    # not destined to be disabled/enabled in
    # the original state
    if ('disabled' in kwargs and mod_source.disabled != kwargs['disabled']):

        s_comps = set(mod_source.comps)
        r_comps = set(repo_comps)
        if s_comps.symmetric_difference(r_comps):
            new_source = sourceslist.SourceEntry(source.line)
            new_source.file = source.file
            new_source.comps = list(r_comps.difference(s_comps))
            source.comps = list(s_comps.difference(r_comps))
            sources.insert(sources.index(source), new_source)
            sources.save()

    for key in kwargs:
        if key in _MODIFY_OK and hasattr(mod_source, key):
            setattr(mod_source, key, kwargs[key])
    sources.save()
    # on changes, explicitly refresh
    refresh_db()
    return {
        repo: {
            'architectures': getattr(mod_source, 'architectures', []),
            'comps': mod_source.comps,
            'disabled': mod_source.disabled,
            'file': mod_source.file,
            'type': mod_source.type,
            'uri': mod_source.uri,
            'line': mod_source.line
        }
    }