예제 #1
0
def remove_tag_inheritance(session, child_tag, parent_tag, check_mode):
    """
    Ensure that a tag inheritance rule does not exist.

    :param session: Koji client session
    :param str child_tag: Koji tag name
    :param str parent_tag: Koji tag name
    :param bool check_mode: don't make any changes
    :return: result (dict)
    """
    result = {'changed': False, 'stdout_lines': []}
    current_inheritance = session.getInheritanceData(child_tag)
    found_rule = {}
    for rule in current_inheritance:
        if rule['name'] == parent_tag:
            found_rule = rule.copy()
            # Mark this rule for deletion
            found_rule['delete link'] = True
    if not found_rule:
        return result
    result['stdout_lines'].append('remove inheritance link:')
    result['stdout_lines'].extend(
        common_koji.describe_inheritance_rule(found_rule))
    result['changed'] = True
    if not check_mode:
        common_koji.ensure_logged_in(session)
        session.setInheritanceData(child_tag, [found_rule])
    return result
예제 #2
0
def ensure_channels(session, host_id, host_name, check_mode, desired_channels):
    """
    Ensure that given host belongs to given channels (and only them).

    :param session: Koji client session
    :param int host_id: Koji host ID
    :param int host_name: Koji host name
    :param bool check_mode: don't make any changes
    :param list desired_channels: channels that the host should belong to
    """
    result = {'changed': False, 'stdout_lines': []}
    common_koji.ensure_logged_in(session)
    current_channels = session.listChannels(host_id)
    current_channels = [channel['name'] for channel in current_channels]
    for channel in current_channels:
        if channel not in desired_channels:
            if not check_mode:
                session.removeHostFromChannel(host_name, channel)
            result['stdout_lines'].append('removed host from channel %s' % channel)
            result['changed'] = True
    for channel in desired_channels:
        if channel not in current_channels:
            if not check_mode:
                session.addHostToChannel(host_name, channel, create=True)
            result['stdout_lines'].append('added host to channel %s' % channel)
            result['changed'] = True
    return result
예제 #3
0
def run_module():
    module_args = dict(
        koji=dict(),
        name=dict(required=True),
        state=dict(choices=['present', 'absent'], default='present'),
    )
    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    if not common_koji.HAS_KOJI:
        module.fail_json(msg='koji is required for this module')

    check_mode = module.check_mode
    params = module.params
    profile = params['koji']
    name = params['name']
    state = params['state']

    session = common_koji.get_session(profile)

    result = {'changed': False}

    if state == 'present':
        btypes = session.listBTypes(query={'name': name})
        if not btypes:
            result['changed'] = True
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.addBType(name)
    elif state == 'absent':
        module.fail_json(msg="Cannot remove Koji build types.",
                         changed=False,
                         rc=1)

    module.exit_json(**result)
예제 #4
0
def ensure_external_repo(session, name, check_mode, url):
    """
    Ensure that this external repo exists in Koji.

    :param session: Koji client session
    :param name: Koji external repo name
    :param check_mode: don't make any changes
    :param url: URL to this external repo
    """
    repoinfo = session.getExternalRepo(name)
    result = {'changed': False, 'stdout_lines': []}
    if not repoinfo:
        if check_mode:
            result['stdout_lines'].append('would create repo %s' % name)
            result['changed'] = True
            return result
        common_koji.ensure_logged_in(session)
        repoinfo = session.createExternalRepo(name, url)
        result['stdout_lines'].append('created repo id %d' % repoinfo['id'])
        result['changed'] = True
        return result
    if repoinfo['url'] != url:
        result['stdout_lines'].append('set url to %s' % url)
        result['changed'] = True
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.editExternalRepo(info=repoinfo['id'], url=url)
    return result
예제 #5
0
def ensure_cg(session, user, name, state, cgs, check_mode):
    """
    Ensure that a content generator and user is present or absent.

    :param session: koji ClientSession
    :param str user: koji user name
    :param str name: content generator name
    :param str state: "present" or "absent"
    :param dict cgs: existing content generators and users
    :param bool check_mode: if True, show what would happen, but don't do it.
    :returns: result
    """
    result = {'changed': False}
    if state == 'present':
        if name not in cgs or user not in cgs[name]['users']:
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.grantCGAccess(user, name, create=True)
            result['changed'] = True
    if state == 'absent':
        if name in cgs and user in cgs[name]['users']:
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.revokeCGAccess(user, name)
            result['changed'] = True
    return result
예제 #6
0
def ensure_unknown_cg(session, user, name, state):
    """
    Ensure that a content generator and user is present or absent.

    This method is for older versions of Koji where we do not have the listCGs
    RPC. This method does not support check_mode.

    :param session: koji ClientSession
    :param str user: koji user name
    :param str name: content generator name
    :param str state: "present" or "absent"
    :returns: result
    """
    result = {'changed': False}
    koji_profile = sys.modules[session.__module__]
    common_koji.ensure_logged_in(session)
    if state == 'present':
        # The "grant" method will at least raise an error if the permission
        # was already granted, so we can set the "changed" result based on
        # that.
        try:
            session.grantCGAccess(user, name, create=True)
            result['changed'] = True
        except koji_profile.GenericError as e:
            if 'User already has access to content generator' not in str(e):
                raise
    if state == 'absent':
        # There's no indication whether this changed anything, so we're going
        # to be pessimistic and say we're always changing it.
        session.revokeCGAccess(user, name)
        result['changed'] = True
    return result
예제 #7
0
def remove_packages(session, tag_name, check_mode, packages):
    result = {'changed': False, 'stdout_lines': []}
    for owner, packages in packages.items():
        for package in packages:
            result['stdout_lines'].append('remove pkg %s' % package)
            result['changed'] = True
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.packageListRemove(tag_name, package, owner)
    return result
예제 #8
0
def remove_external_repos(session, tag_name, repos):
    """
    Remove all these external repos from this Koji tag.

    :param session: Koji client session
    :param str tag_name: Koji tag name
    :param list repos: list of repository names (str) to remove.
    """
    # TODO: refactor this loop to one single multicall.
    common_koji.ensure_logged_in(session)
    for name in repos:
        session.removeExternalRepoFromTag(tag_name, name)
예제 #9
0
def ensure_inheritance(session, tag_name, tag_id, check_mode, inheritance):
    """
    Ensure that these inheritance rules are configured on this Koji tag.

    :param session: Koji client session
    :param str tag_name: Koji tag name
    :param int tag_id: Koji tag ID
    :param bool check_mode: don't make any changes
    :param list inheritance: ensure these rules are set, and no others
    """
    rules = []
    result = {'changed': False, 'stdout_lines': []}
    for rule in sorted(inheritance, key=lambda i: i['priority']):
        parent_name = rule['parent']
        parent_taginfo = session.getTag(parent_name)
        if not parent_taginfo:
            msg = "parent tag '%s' not found" % parent_name
            if check_mode:
                result['stdout_lines'].append(msg)
                # spoof to allow continuation
                parent_taginfo = {'id': 0}
            else:
                raise ValueError(msg)
        parent_id = parent_taginfo['id']
        # maxdepth: treat empty strings the same as None
        maxdepth = rule.get('maxdepth')
        if maxdepth == '':
            maxdepth = None
        if isinstance(maxdepth, string_types):
            maxdepth = int(maxdepth)
        new_rule = {
            'child_id': tag_id,
            'intransitive': rule.get('intransitive', False),
            'maxdepth': maxdepth,
            'name': parent_name,
            'noconfig': rule.get('noconfig', False),
            'parent_id': parent_id,
            'pkg_filter': rule.get('pkg_filter', ''),
            'priority': rule['priority']
        }
        rules.append(new_rule)
    current_inheritance = session.getInheritanceData(tag_name)
    if current_inheritance != rules:
        result['stdout_lines'].extend(
            ('current inheritance:', ) +
            common_koji.describe_inheritance(current_inheritance) +
            ('new inheritance:', ) + common_koji.describe_inheritance(rules))
        result['changed'] = True
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.setInheritanceData(tag_name, rules, clear=True)
    return result
예제 #10
0
def run_module():
    module_args = dict(
        koji=dict(type='str', required=False),
        name=dict(type='str', required=True),
        user=dict(type='str', required=True),
        state=dict(type='str', required=False, default='present'),
    )
    module = AnsibleModule(
        argument_spec=module_args,
        # check mode needs https://pagure.io/koji/pull-request/1160
        supports_check_mode=False
    )

    if not common_koji.HAS_KOJI:
        module.fail_json(msg='koji is required for this module')

    params = module.params
    profile = params['koji']
    name = params['name']
    user = params['user']
    state = params['state']

    session = common_koji.get_session(profile)

    result = {'changed': False}

    # There are no "get" methods for content generator information, so we must
    # send the changes to Koji every time.
    # in-progress "listCGs" pull request:
    # https://pagure.io/koji/pull-request/1160

    common_koji.ensure_logged_in(session)

    if state == 'present':
        # The "grant" method will at least raise an error if the permission was
        # already granted, so we can set the "changed" result based on that.
        try:
            session.grantCGAccess(user, name, create=True)
            result['changed'] = True
        except common_koji.koji.GenericError as e:
            if 'User already has access to content generator' not in str(e):
                raise
    elif state == 'absent':
        # There's no indication whether this changed anything, so we're going
        # to be pessimistic and say we're always changing it.
        session.revokeCGAccess(user, name)
        result['changed'] = True
    else:
        module.fail_json(msg="State must be 'present' or 'absent'.",
                         changed=False, rc=1)

    module.exit_json(**result)
예제 #11
0
def delete_target(session, name, check_mode):
    """ Ensure that this tag is deleted from Koji. """
    targetinfo = session.getBuildTarget(name)
    result = dict(
        stdout='',
        changed=False,
    )
    if targetinfo:
        common_koji.ensure_logged_in(session)
        session.deleteBuildTarget(targetinfo)
        result['stdout'] = 'deleted target %d' % targetinfo['id']
        result['changed'] = True
    return result
예제 #12
0
def add_external_repos(session, tag_name, repos):
    """
    Add all these external repos to this Koji tag.

    :param session: Koji client session
    :param str tag_name: Koji tag name
    :param list repos: list of dicts, one for each repository to add. These
                       dicts are kwargs to the addExternalRepoToTag RPC.
    """
    # TODO: refactor this loop to one single multicall.
    common_koji.ensure_logged_in(session)
    for repo in repos:
        session.addExternalRepoToTag(tag_name, **repo)
예제 #13
0
def add_tag_inheritance(session, child_tag, parent_tag, priority, maxdepth,
                        check_mode):
    """
    Ensure that a tag inheritance rule exists.

    :param session: Koji client session
    :param str child_tag: Koji tag name
    :param str parent_tag: Koji tag name
    :param int priority: Priority of this parent for this child
    :param int maxdepth: Max depth of the inheritance
    :param bool check_mode: don't make any changes
    :return: result (dict)
    """
    result = {'changed': False, 'stdout_lines': []}
    data = get_ids_and_inheritance(session, child_tag, parent_tag)
    child_id, parent_id, current_inheritance = data
    if not child_id:
        msg = 'child tag %s not found' % child_tag
        if check_mode:
            result['stdout_lines'].append(msg)
        else:
            raise ValueError(msg)
    if not parent_id:
        msg = 'parent tag %s not found' % parent_tag
        if check_mode:
            result['stdout_lines'].append(msg)
        else:
            raise ValueError(msg)

    new_rule = generate_new_rule(child_id, parent_tag, parent_id, priority,
                                 maxdepth)
    new_rules = [new_rule]
    for rule in current_inheritance:
        if rule == new_rule:
            return result
        if rule['priority'] == priority:
            delete_rule = rule.copy()
            # Mark this rule for deletion
            delete_rule['delete link'] = True
            new_rules.insert(0, delete_rule)
            result['stdout_lines'].append(
                'remove parent %s (%d)' %
                (delete_rule['name'], delete_rule['priority']))
    result['stdout_lines'].append('set parent %s (%d)' %
                                  (parent_tag, priority))
    result['changed'] = True
    if not check_mode:
        common_koji.ensure_logged_in(session)
        session.setInheritanceData(child_tag, new_rules)
    return result
예제 #14
0
def delete_tag(session, name, check_mode):
    """ Ensure that this tag is deleted from Koji. """
    taginfo = session.getTag(name)
    result = dict(
        stdout='',
        changed=False,
    )
    if taginfo:
        result['stdout'] = 'deleted tag %d' % taginfo['id']
        result['changed'] = True
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.deleteTag(name)
    return result
예제 #15
0
def delete_external_repo(session, name, check_mode):
    """ Ensure that this external_repo is deleted from Koji. """
    repoinfo = session.getExternalRepo(name)
    result = dict(
        stdout='',
        changed=False,
    )
    if repoinfo:
        result['stdout'] = 'deleted external repo %s' % name
        result['changed'] = True
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.deleteExternalRepo(name)
    return result
예제 #16
0
def ensure_packages(session, tag_name, tag_id, check_mode, packages):
    """
    Ensure that these packages are configured on this Koji tag.

    :param session: Koji client session
    :param str tag_name: Koji tag name
    :param int tag_id: Koji tag ID
    :param bool check_mode: don't make any changes
    :param dict packages: Ensure that these owners and package names are
                          configured for this tag.
    """
    result = {'changed': False, 'stdout_lines': []}
    # Note: this in particular could really benefit from koji's
    # multicalls...
    common_koji.ensure_logged_in(session)
    current_pkgs = session.listPackages(tagID=tag_id)
    current_names = set([pkg['package_name'] for pkg in current_pkgs])
    # Create a "current_owned" dict to compare with what's in Ansible.
    current_owned = defaultdict(set)
    for pkg in current_pkgs:
        owner = pkg['owner_name']
        pkg_name = pkg['package_name']
        current_owned[owner].add(pkg_name)
    for owner, owned in packages.items():
        for package in owned:
            if package not in current_names:
                # The package was missing from the tag entirely.
                if not check_mode:
                    session.packageListAdd(tag_name, package, owner)
                result['stdout_lines'].append('added pkg %s' % package)
                result['changed'] = True
            else:
                # The package is already in this tag.
                # Verify ownership.
                if package not in current_owned.get(owner, []):
                    if not check_mode:
                        session.packageListSetOwner(tag_name, package, owner)
                    result['stdout_lines'].append('set %s owner %s' %
                                                  (package, owner))
                    result['changed'] = True
    # Delete any packages not in Ansible.
    all_names = [name for names in packages.values() for name in names]
    delete_names = set(current_names) - set(all_names)
    for package in delete_names:
        result['stdout_lines'].append('remove pkg %s' % package)
        result['changed'] = True
        if not check_mode:
            session.packageListRemove(tag_name, package, owner)
    return result
예제 #17
0
def ensure_groups(session, tag_id, check_mode, desired_groups):
    """
    Ensure that these groups are configured on this Koji tag.

    :param session: Koji client session
    :param int tag_id: Koji tag ID
    :param bool check_mode: don't make any changes
    :param dict desired_groups: ensure these groups are set (?)
    """
    result = {'changed': False, 'stdout_lines': []}
    common_koji.ensure_logged_in(session)
    current_groups = session.getTagGroups(tag_id)
    for group in current_groups:
        if group['tag_id'] == tag_id and group['name'] not in desired_groups:
            if not check_mode:
                session.groupListRemove(tag_id, group['name'])
            result['stdout_lines'].append('removed group %s' % group['name'])
            result['changed'] = True
    for group_name, desired_pkgs in desired_groups.items():
        for group in current_groups:
            if group['name'] == group_name:
                current_pkgs = {
                    entry['package']: entry['tag_id']
                    for entry in group['packagelist']
                }
                break
        else:
            current_pkgs = {}
            if not check_mode:
                session.groupListAdd(tag_id, group_name)
            result['stdout_lines'].append('added group %s' % group_name)
            result['changed'] = True

        for package, pkg_tag_id in current_pkgs.items():
            if pkg_tag_id == tag_id and package not in desired_pkgs:
                if not check_mode:
                    session.groupPackageListRemove(tag_id, group_name, package)
                result['stdout_lines'].append('removed pkg %s from group %s' %
                                              (package, group_name))
                result['changed'] = True
        for package in desired_pkgs:
            if package not in current_pkgs:
                if not check_mode:
                    session.groupPackageListAdd(tag_id, group_name, package)
                result['stdout_lines'].append('added pkg %s to group %s' %
                                              (package, group_name))
                result['changed'] = True
    return result
예제 #18
0
def do_call(session, name, args, login):
    """
    Execute a Koji RPC.

    :param session: Koji client session
    :param str name: Name of the RPC
    :param args: list or dict of arguments to this RPC.
    :param bool login: Whether to log in for this call or not.
    """
    result = {'changed': True}
    if login:
        common_koji.ensure_logged_in(session)
    call = getattr(session, name)
    if isinstance(args, dict):
        data = call(**args)
    else:
        data = call(*args)
    result['data'] = data
    return result
예제 #19
0
def run_module():
    module_args = dict(
        koji=dict(type='str', required=False),
        name=dict(type='str', required=True),
        description=dict(type='str', required=True),
        extensions=dict(type='str', required=True),
        state=dict(type='str', required=False, default='present'),
    )
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    if not common_koji.HAS_KOJI:
        module.fail_json(msg='koji is required for this module')

    check_mode = module.check_mode
    params = module.params
    profile = params['koji']
    name = params['name']
    description = params['description']
    extensions = params['extensions']
    state = params['state']

    session = common_koji.get_session(profile)

    result = {'changed': False}

    if state == 'present':
        if not session.getArchiveType(type_name=name):
            result['changed'] = True
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.addArchiveType(name, description, extensions)
    elif state == 'absent':
        module.fail_json(msg="Cannot remove Koji archive types.",
                         changed=False, rc=1)
    else:
        module.fail_json(msg="State must be 'present' or 'absent'.",
                         changed=False, rc=1)

    module.exit_json(**result)
예제 #20
0
def ensure_inheritance(session, tag_name, tag_id, check_mode, inheritance):
    """
    Ensure that these inheritance rules are configured on this Koji tag.

    :param session: Koji client session
    :param str tag_name: Koji tag name
    :param int tag_id: Koji tag ID
    :param bool check_mode: don't make any changes
    :param list inheritance: ensure these rules are set, and no others
    """
    result = {'changed': False, 'stdout_lines': []}

    # resolve parent tag IDs
    rules = []
    for rule in normalize_inheritance(inheritance):
        parent_name = rule['name']
        parent_taginfo = session.getTag(parent_name)
        if not parent_taginfo:
            msg = "parent tag '%s' not found" % parent_name
            if check_mode:
                result['stdout_lines'].append(msg)
                # spoof to allow continuation
                parent_taginfo = {'id': 0}
            else:
                raise ValueError(msg)
        parent_id = parent_taginfo['id']
        rules.append(dict(rule, child_id=tag_id, parent_id=parent_id))

    current_inheritance = session.getInheritanceData(tag_name)
    if current_inheritance != rules:
        result['stdout_lines'].extend(
                ('current inheritance:',)
                + common_koji.describe_inheritance(current_inheritance)
                + ('new inheritance:',)
                + common_koji.describe_inheritance(rules))
        result['changed'] = True
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.setInheritanceData(tag_name, rules, clear=True)
    return result
예제 #21
0
def ensure_user(session, name, check_mode, state, permissions, krb_principals):
    """
    Ensure that this user is configured in Koji.

    :param session: Koji client session
    :param str name: Koji user name
    :param bool check_mode: don't make any changes
    :param str state: "enabled" or "disabled"
    :param list permissions: list of permissions for this user.
    :param list krb_principals: list of kerberos principals for this user, or
                None.
    """
    result = {'changed': False, 'stdout_lines': []}
    if state == 'enabled':
        desired_status = common_koji.koji.USER_STATUS['NORMAL']
    else:
        desired_status = common_koji.koji.USER_STATUS['BLOCKED']
    user = session.getUser(name)
    if not user:
        result['changed'] = True
        result['stdout_lines'] = ['created %s user' % name]
        if check_mode:
            return result
        common_koji.ensure_logged_in(session)
        krb_principal = krb_principals[0] if krb_principals else None
        id_ = session.createUser(name, desired_status, krb_principal)
        user = session.getUser(id_)
    if user['status'] != desired_status:
        result['changed'] = True
        result['stdout_lines'] = ['%s %s user' % (state, name)]
        if not check_mode:
            common_koji.ensure_logged_in(session)
        if state == 'enabled':
            session.enableUser(name)
        else:
            session.disableUser(name)
    if permissions is None:
        return result
    current_perms = session.getUserPerms(user['id'])
    to_grant = set(permissions) - set(current_perms)
    to_revoke = set(current_perms) - set(permissions)
    if to_grant or to_revoke:
        result['changed'] = True
        if not check_mode:
            common_koji.ensure_logged_in(session)
    for permission in to_grant:
        result['stdout_lines'].append('grant %s' % permission)
        if not check_mode:
            session.grantPermission(name, permission, True)
    for permission in to_revoke:
        result['stdout_lines'].append('revoke %s' % permission)
        if not check_mode:
            session.revokePermission(name, permission)
    if krb_principals is not None:
        changes = common_koji.ensure_krb_principals(session, user, check_mode,
                                                    krb_principals)
        if changes:
            result['changed'] = True
            result['stdout_lines'].extend(changes)
    return result
예제 #22
0
def run_module():
    module_args = dict(
        koji=dict(type='str', required=False),
        name=dict(type='str', required=True),
        state=dict(type='str', required=False, default='present'),
    )
    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    if not common_koji.HAS_KOJI:
        module.fail_json(msg='koji is required for this module')

    check_mode = module.check_mode
    params = module.params
    profile = params['koji']
    name = params['name']
    state = params['state']

    session = common_koji.get_session(profile)

    result = {'changed': False}

    if state == 'present':
        btype_data = session.listBTypes()
        btypes = [data['name'] for data in btype_data]
        if name not in btypes:
            result['changed'] = True
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.addBType(name)
    elif state == 'absent':
        module.fail_json(msg="Cannot remove Koji build types.",
                         changed=False,
                         rc=1)
    else:
        module.fail_json(msg="State must be 'present' or 'absent'.",
                         changed=False,
                         rc=1)

    module.exit_json(**result)
예제 #23
0
def ensure_host(session, name, check_mode, state, arches, krb_principal,
                **kwargs):
    """
    Ensure that this host is configured in Koji.

    :param session: Koji client session
    :param str name: Koji builder host name
    :param bool check_mode: don't make any changes
    :param str state: "enabled" or "disabled"
    :param list arches: list of arches for this builder.
    :param str krb_principal: custom kerberos principal, or None
    :param **kwargs: Pass remaining kwargs directly into Koji's editHost RPC.
    """
    result = {'changed': False}
    host = session.getHost(name)
    if not host:
        result['changed'] = True
        if check_mode:
            return result
        common_koji.ensure_logged_in(session)
        id_ = session.addHost(name, arches, krb_principal)
        host = session.getHost(id_)
    if state == 'enabled':
        if not host['enabled']:
            result['changed'] = True
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.enableHost(name)
    if state == 'disabled':
        if host['enabled']:
            result['changed'] = True
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.disableHost(name)
    edits = {}
    if ' '.join(arches) != host['arches']:
        edits['arches'] = ' '.join(arches)
    for key, value in kwargs.items():
        if value is None:
            continue  # Ansible did not set this parameter.
        if key in host and kwargs[key] != host[key]:
            edits[key] = value
    if edits:
        result['changed'] = True
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.editHost(name, **edits)
    return result
예제 #24
0
def ensure_inheritance(session, tag_name, tag_id, check_mode, inheritance):
    """
    Ensure that these inheritance rules are configured on this Koji tag.

    :param session: Koji client session
    :param str tag_name: Koji tag name
    :param int tag_id: Koji tag ID
    :param bool check_mode: don't make any changes
    :param list inheritance: ensure these rules are set, and no others
    """
    rules = []
    result = {'changed': False, 'stdout_lines': []}
    for rule in sorted(inheritance, key=lambda i: i['priority']):
        parent_name = rule['parent']
        parent_taginfo = session.getTag(parent_name)
        if not parent_taginfo:
            raise ValueError("parent tag '%s' not found" % parent_name)
        parent_id = parent_taginfo['id']
        new_rule = {
            'child_id': tag_id,
            'intransitive': False,
            'maxdepth': None,
            'name': parent_name,
            'noconfig': False,
            'parent_id': parent_id,
            'pkg_filter': '',
            'priority': rule['priority']
        }
        rules.append(new_rule)
    current_inheritance = session.getInheritanceData(tag_name)
    if current_inheritance != rules:
        result['stdout_lines'].append('inheritance is %s' % inheritance)
        result['changed'] = True
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.setInheritanceData(tag_name, rules, clear=True)
    return result
예제 #25
0
def ensure_target(session, name, check_mode, build_tag, dest_tag):
    """
    Ensure that this target exists in Koji.

    :param session: Koji client session
    :param name: Koji target name
    :param check_mode: don't make any changes
    :param build_tag: Koji build tag name, eg. "f29-build"
    :param dest_tag: Koji destination tag name, eg "f29-updates-candidate"
    """
    targetinfo = session.getBuildTarget(name)
    result = {'changed': False, 'stdout_lines': []}
    if not targetinfo:
        result['changed'] = True
        if check_mode:
            result['stdout_lines'].append('would create target %s' % name)
            return result
        common_koji.ensure_logged_in(session)
        session.createBuildTarget(name, build_tag, dest_tag)
        targetinfo = session.getBuildTarget(name)
        result['stdout_lines'].append('created target %s' % targetinfo['id'])
    # Ensure the build and destination tags are set for this target.
    needs_edit = False
    if build_tag != targetinfo['build_tag_name']:
        needs_edit = True
        result['stdout_lines'].append('build_tag_name: %s' % build_tag)
    if dest_tag != targetinfo['dest_tag_name']:
        needs_edit = True
        result['stdout_lines'].append('dest_tag_name: %s' % dest_tag)
    if needs_edit:
        result['changed'] = True
        if check_mode:
            return result
        common_koji.ensure_logged_in(session)
        session.editBuildTarget(name, name, build_tag, dest_tag)
    return result
예제 #26
0
def ensure_external_repos(session, tag_name, check_mode, repos):
    """
    Ensure that these external repos are configured on this Koji tag.

    :param session: Koji client session
    :param str tag_name: Koji tag name
    :param bool check_mode: don't make any changes
    :param list repos: ensure these external repos are set, and no others.
    """
    result = {'changed': False, 'stdout_lines': []}
    validate_repos(repos)
    current_repo_list = session.getTagExternalRepos(tag_name)
    current = {repo['external_repo_name']: repo for repo in current_repo_list}
    current_priorities = {
        str(repo['priority']): repo
        for repo in current_repo_list
    }
    for repo in sorted(repos, key=lambda r: r['priority']):
        repo_name = repo['repo']
        repo_priority = repo['priority']
        if repo_name in current:
            # The repo is present for this tag.
            # Now ensure the priority is correct.
            if repo_priority == current[repo_name]['priority']:
                continue
            result['changed'] = True
            msg = 'set %s repo priority to %i' % (repo_name, repo_priority)
            result['stdout_lines'].append(msg)
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.editTagExternalRepo(tag_name, repo_name, repo_priority)
            continue
        elif str(repo_priority) in current_priorities:
            # No need to check for name equivalence here; it would already
            # have happened
            result['changed'] = True
            msg = 'set repo at priority %i to %s' % (repo_priority, repo_name)
            result['stdout_lines'].append(msg)
            if not check_mode:
                common_koji.ensure_logged_in(session)
                same_priority_repo = current_priorities.get(
                    str(repo_priority)).get('external_repo_name')
                session.removeExternalRepoFromTag(tag_name, same_priority_repo)
                session.addExternalRepoToTag(tag_name, repo_name,
                                             repo_priority)
                # Prevent duplicate attempts
                del current_priorities[str(repo_priority)]
            continue
        result['changed'] = True
        msg = 'add %s external repo to %s' % (repo_name, tag_name)
        result['stdout_lines'].append(msg)
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.addExternalRepoToTag(tag_name, repo_name, repo_priority)
    # Find the repos to remove from this tag.
    repo_names = [repo['repo'] for repo in repos]
    current_names = current.keys()
    repos_to_remove = set(current_names) - set(repo_names)
    for repo_name in repos_to_remove:
        result['changed'] = True
        msg = 'removed %s repo from %s tag' % (repo_name, tag_name)
        result['stdout_lines'].append(msg)
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.removeExternalRepoFromTag(tag_name, repo_name)
    return result
예제 #27
0
def ensure_host(session, name, check_mode, state, arches, krb_principal,
                channels, **kwargs):
    """
    Ensure that this host is configured in Koji.

    :param session: Koji client session
    :param str name: Koji builder host name
    :param bool check_mode: don't make any changes
    :param str state: "enabled" or "disabled"
    :param list arches: list of arches for this builder.
    :param str krb_principal: custom kerberos principal, or None
    :param list chanels: list of channels this host should belong to.
    :param **kwargs: Pass remaining kwargs directly into Koji's editHost RPC.
    """
    result = {'changed': False, 'stdout_lines': []}
    host = session.getHost(name)
    if not host:
        result['changed'] = True
        result['stdout_lines'].append('created host')
        if check_mode:
            return result
        common_koji.ensure_logged_in(session)
        id_ = session.addHost(name, arches, krb_principal)
        host = session.getHost(id_)
    if state == 'enabled':
        if not host['enabled']:
            result['changed'] = True
            result['stdout_lines'].append('enabled host')
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.enableHost(name)
    if state == 'disabled':
        if host['enabled']:
            result['changed'] = True
            result['stdout_lines'].append('disabled host')
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.disableHost(name)
    edits = {}
    if ' '.join(arches) != host['arches']:
        edits['arches'] = ' '.join(arches)
    for key, value in kwargs.items():
        if value is None:
            continue  # Ansible did not set this parameter.
        if key in host and kwargs[key] != host[key]:
            edits[key] = value
    if edits:
        result['changed'] = True
        for edit in edits.keys():
            result['stdout_lines'].append('edited host %s' % edit)
        if not check_mode:
            common_koji.ensure_logged_in(session)
            session.editHost(name, **edits)

    # Ensure host is member of desired channels.
    if channels not in (None, ''):
        channels_result = ensure_channels(session, host['id'],
                                          name, check_mode, channels)
        if channels_result['changed']:
            result['changed'] = True
        result['stdout_lines'].extend(channels_result['stdout_lines'])

    return result
예제 #28
0
def ensure_tag(session, name, check_mode, inheritance, external_repos,
               packages, groups, **kwargs):
    """
    Ensure that this tag exists in Koji.

    :param session: Koji client session
    :param name: Koji tag name
    :param check_mode: don't make any changes
    :param inheritance: Koji tag inheritance settings. These will be translated
                        for Koji's setInheritanceData RPC.
    :param external_repos: Koji external repos to set for this tag.
    :param packages: dict of packages to add ("whitelist") for this tag.
                     If this is an empty dict, we don't touch the package list
                     for this tag.
    :param groups: dict of comps groups to set for this tag.
    :param **kwargs: Pass remaining kwargs directly into Koji's createTag and
                     editTag2 RPCs.
    """
    taginfo = session.getTag(name)
    result = {'changed': False, 'stdout_lines': []}
    if not taginfo:
        if check_mode:
            result['stdout_lines'].append('would create tag %s' % name)
            result['changed'] = True
            return result
        common_koji.ensure_logged_in(session)
        if 'perm' in kwargs and kwargs['perm']:
            kwargs['perm'] = common_koji.get_perm_id(session, kwargs['perm'])
        id_ = session.createTag(name, parent=None, **kwargs)
        result['stdout_lines'].append('created tag id %d' % id_)
        result['changed'] = True
        taginfo = {'id': id_}  # populate for inheritance management below
    else:
        # The tag name already exists. Ensure all the parameters are set.
        edits = {}
        edit_log = []
        for key, value in kwargs.items():
            if taginfo[key] != value and value is not None:
                edits[key] = value
                edit_log.append('%s: changed %s from "%s" to "%s"' %
                                (name, key, taginfo[key], value))
        # Find out which "extra" items we must explicitly remove
        # ("remove_extra" argument to editTag2).
        if 'extra' in kwargs and kwargs['extra'] is not None:
            for key in taginfo['extra']:
                if key not in kwargs['extra']:
                    if 'remove_extra' not in edits:
                        edits['remove_extra'] = []
                    edits['remove_extra'].append(key)
            if 'remove_extra' in edits:
                edit_log.append('%s: remove extra fields "%s"' %
                                (name, '", "'.join(edits['remove_extra'])))
        if edits:
            result['stdout_lines'].extend(edit_log)
            result['changed'] = True
            if not check_mode:
                common_koji.ensure_logged_in(session)
                session.editTag2(name, **edits)

    # Ensure inheritance rules are all set.
    if inheritance not in (None, ['']):
        inheritance_result = ensure_inheritance(session, name, taginfo['id'],
                                                check_mode, inheritance)
        if inheritance_result['changed']:
            result['changed'] = True
        result['stdout_lines'].extend(inheritance_result['stdout_lines'])

    # Ensure external repos.
    if external_repos not in (None, ['']):
        repos_result = ensure_external_repos(session, name, check_mode,
                                             external_repos)
        if repos_result['changed']:
            result['changed'] = True
        result['stdout_lines'].extend(repos_result['stdout_lines'])

    # Ensure package list.
    if packages not in (None, ''):
        if not isinstance(packages, dict):
            raise ValueError('packages must be a dict')
        packages_result = ensure_packages(session, name, taginfo['id'],
                                          check_mode, packages)
        if packages_result['changed']:
            result['changed'] = True
        result['stdout_lines'].extend(packages_result['stdout_lines'])

    # Ensure group list.
    if groups not in (None, ''):
        if not isinstance(groups, dict):
            raise ValueError('groups must be a dict')
        groups_result = ensure_groups(session, taginfo['id'], check_mode,
                                      groups)
        if groups_result['changed']:
            result['changed'] = True
        result['stdout_lines'].extend(groups_result['stdout_lines'])

    return result
예제 #29
0
def add_tag_inheritance(session, child_tag, parent_tag, priority, maxdepth,
                        pkg_filter, intransitive, noconfig, check_mode):
    """
    Ensure that a tag inheritance rule exists.

    :param session: Koji client session
    :param str child_tag: Koji tag name
    :param str parent_tag: Koji tag name
    :param int priority: Priority of this parent for this child
    :param int maxdepth: Max depth of the inheritance
    :param str pkg_filter: Regular expression string of package names to include
    :param bool intransitive: Don't allow this inheritance link to be inherited
    :param bool noconfig: Prevent tag options ("extra") from being inherited
    :param bool check_mode: don't make any changes
    :return: result (dict)
    """
    result = {'changed': False, 'stdout_lines': []}
    data = get_ids_and_inheritance(session, child_tag, parent_tag)
    child_id, parent_id, current_inheritance = data
    if not child_id:
        msg = 'child tag %s not found' % child_tag
        if check_mode:
            result['stdout_lines'].append(msg)
        else:
            raise ValueError(msg)
    if not parent_id:
        msg = 'parent tag %s not found' % parent_tag
        if check_mode:
            result['stdout_lines'].append(msg)
        else:
            raise ValueError(msg)

    new_rule = generate_new_rule(child_id, parent_tag, parent_id, priority,
                                 maxdepth, pkg_filter, intransitive, noconfig)
    new_rules = [new_rule]
    for rule in current_inheritance:
        if rule == new_rule:
            return result
        if rule['priority'] == priority:
            # prefix taginfo-style inheritance strings with diff-like +/-
            result['stdout_lines'].append('dissimilar rules:')
            result['stdout_lines'].extend(
                map(lambda r: ' -' + r,
                    common_koji.describe_inheritance_rule(rule)))
            result['stdout_lines'].extend(
                map(lambda r: ' +' + r,
                    common_koji.describe_inheritance_rule(new_rule)))
            delete_rule = rule.copy()
            # Mark this rule for deletion
            delete_rule['delete link'] = True
            new_rules.insert(0, delete_rule)

    if len(new_rules) > 1:
        result['stdout_lines'].append('remove inheritance link:')
        result['stdout_lines'].extend(
            common_koji.describe_inheritance(new_rules[:-1]))
    result['stdout_lines'].append('add inheritance link:')
    result['stdout_lines'].extend(
        common_koji.describe_inheritance_rule(new_rule))
    result['changed'] = True
    if not check_mode:
        common_koji.ensure_logged_in(session)
        session.setInheritanceData(child_tag, new_rules)
    return result