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
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
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)
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
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
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
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
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)
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
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)
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
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)
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
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
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
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
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
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
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)
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
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
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)
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
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
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
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
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
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
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