|
|
6e61fb |
#!/usr/bin/python
|
|
|
6e61fb |
from ansible.module_utils.basic import AnsibleModule
|
|
|
6e61fb |
from collections import defaultdict
|
|
|
6e61fb |
from ansible.module_utils import common_koji
|
|
|
6e61fb |
from ansible.module_utils.six import string_types
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
ANSIBLE_METADATA = {
|
|
|
6e61fb |
'metadata_version': '1.0',
|
|
|
6e61fb |
'status': ['preview'],
|
|
|
6e61fb |
'supported_by': 'community'
|
|
|
6e61fb |
}
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
DOCUMENTATION = '''
|
|
|
6e61fb |
---
|
|
|
6e61fb |
module: koji_tag
|
|
|
6e61fb |
|
|
|
6e61fb |
short_description: Create and manage Koji tags
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- Create and manage Koji tags
|
|
|
6e61fb |
options:
|
|
|
6e61fb |
name:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- The name of the Koji tag to create and manage.
|
|
|
6e61fb |
required: true
|
|
|
6e61fb |
inheritance:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- How to set inheritance. what happens when it's unset.
|
|
|
6e61fb |
external_repos:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- list of Koji external repos to set for this tag. Each element of the
|
|
|
6e61fb |
list should have a "repo" (the external repo name) and "priority"
|
|
|
6e61fb |
(integer).
|
|
|
6e61fb |
packages:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- dict of package owners and the a lists of packages each owner
|
|
|
6e61fb |
maintains.
|
|
|
6e61fb |
groups:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- A tag's "groups" tell Koji what packages will be present in the
|
|
|
6e61fb |
tag's buildroot. For example, the "build" group defines the packages
|
|
|
6e61fb |
that Koji will put into a "build" task's buildroot. You may set other
|
|
|
6e61fb |
package groups on a tag as well, like "srpm-build" or
|
|
|
6e61fb |
"applicance-build".
|
|
|
6e61fb |
- This should be a dict of groups and packages to set for this tag.
|
|
|
6e61fb |
Each dict key will be the name of the group. Each dict value should
|
|
|
6e61fb |
be a list of package names to include in the comps for this group.
|
|
|
6e61fb |
- If a group or package defined in this field is already applicable for
|
|
|
6e61fb |
a tag due to inheritance, Koji will not allow it to be added to the
|
|
|
6e61fb |
tag, but will instead silently ignore it. Conversely, groups and
|
|
|
6e61fb |
packages that are inherited in this field are not removed if they are
|
|
|
6e61fb |
left unspecified. Therefore, this field will only have an effect if it
|
|
|
6e61fb |
includes groups and packages that are unique to this tag (i.e., not
|
|
|
6e61fb |
inherited).
|
|
|
6e61fb |
- This does not support advanced comps group operations, like
|
|
|
6e61fb |
configuring extra options on groups, or blocking packages in groups.
|
|
|
6e61fb |
If you need that level of control over comps groups, you will need
|
|
|
6e61fb |
to import a full comps XML file, outside of this Ansible module.
|
|
|
6e61fb |
arches:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- space-separated string of arches this Koji tag supports.
|
|
|
6e61fb |
- Note, the order in which you specify architectures does matter in a
|
|
|
6e61fb |
few subtle cases. For example, the SRPM that Koji includes in the
|
|
|
6e61fb |
build is the one built on the first arch in this list. Likewise,
|
|
|
6e61fb |
rpmdiff compares RPMs built on the first arch with RPMs built on
|
|
|
6e61fb |
other arches.
|
|
|
6e61fb |
perm:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- permission (string or int) for this Koji tag.
|
|
|
6e61fb |
locked:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- whether to lock this tag or not.
|
|
|
6e61fb |
choices: [true, false]
|
|
|
6e61fb |
default: false
|
|
|
6e61fb |
maven_support:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- whether Maven repos should be generated for the tag.
|
|
|
6e61fb |
choices: [true, false]
|
|
|
6e61fb |
default: false
|
|
|
6e61fb |
maven_include_all:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- include every build in this tag (including multiple versions of the
|
|
|
6e61fb |
same package) in the Maven repo.
|
|
|
6e61fb |
choices: [true, false]
|
|
|
6e61fb |
default: false
|
|
|
6e61fb |
extra:
|
|
|
6e61fb |
description:
|
|
|
6e61fb |
- set any extra parameters on this tag.
|
|
|
6e61fb |
requirements:
|
|
|
6e61fb |
- "python >= 2.7"
|
|
|
6e61fb |
- "koji"
|
|
|
6e61fb |
'''
|
|
|
6e61fb |
|
|
|
6e61fb |
EXAMPLES = '''
|
|
|
6e61fb |
- name: create a main koji tag and candidate tag
|
|
|
6e61fb |
hosts: localhost
|
|
|
6e61fb |
tasks:
|
|
|
6e61fb |
- name: Create a main product koji tag
|
|
|
6e61fb |
koji_tag:
|
|
|
6e61fb |
koji: kojidev
|
|
|
6e61fb |
name: ceph-3.1-rhel-7
|
|
|
6e61fb |
arches: x86_64
|
|
|
6e61fb |
state: present
|
|
|
6e61fb |
packages:
|
|
|
6e61fb |
kdreyer:
|
|
|
6e61fb |
- ansible
|
|
|
6e61fb |
- ceph
|
|
|
6e61fb |
- ceph-ansible
|
|
|
6e61fb |
|
|
|
6e61fb |
- name: Create a candidate koji tag
|
|
|
6e61fb |
koji_tag:
|
|
|
6e61fb |
koji: kojidev
|
|
|
6e61fb |
name: ceph-3.1-rhel-7-candidate
|
|
|
6e61fb |
state: present
|
|
|
6e61fb |
inheritance:
|
|
|
6e61fb |
- parent: ceph-3.1-rhel-7
|
|
|
6e61fb |
priority: 0
|
|
|
6e61fb |
|
|
|
6e61fb |
- name: Create a tag that uses an external repo
|
|
|
6e61fb |
koji_tag:
|
|
|
6e61fb |
koji: kojidev
|
|
|
6e61fb |
name: storage7-ceph-nautilus-el7-build
|
|
|
6e61fb |
state: present
|
|
|
6e61fb |
external_repos:
|
|
|
6e61fb |
- repo: centos7-cr
|
|
|
6e61fb |
priority: 5
|
|
|
6e61fb |
|
|
|
6e61fb |
- name: Create a tag that uses comps groups
|
|
|
6e61fb |
koji_tag:
|
|
|
6e61fb |
name: foo-el7-build
|
|
|
6e61fb |
groups:
|
|
|
6e61fb |
srpm-build:
|
|
|
6e61fb |
- rpm-build
|
|
|
6e61fb |
- fedpkg
|
|
|
6e61fb |
'''
|
|
|
6e61fb |
|
|
|
6e61fb |
RETURN = ''' # '''
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
class DuplicateNameError(Exception):
|
|
|
6e61fb |
""" The user specified two external repos with the same name. """
|
|
|
6e61fb |
pass
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
class DuplicatePriorityError(Exception):
|
|
|
6e61fb |
""" The user specified two external repos with the same priority. """
|
|
|
6e61fb |
pass
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def validate_repos(repos):
|
|
|
6e61fb |
"""Ensure that each external repository has unique name and priority
|
|
|
6e61fb |
values.
|
|
|
6e61fb |
|
|
|
6e61fb |
This prevents the user from accidentally specifying two or more external
|
|
|
6e61fb |
repositories with the same name or priority.
|
|
|
6e61fb |
|
|
|
6e61fb |
:param repos: list of repository dicts
|
|
|
6e61fb |
:raises: DuplicatePriorityError if two repos have the same priority.
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
names = set()
|
|
|
6e61fb |
priorities = set()
|
|
|
6e61fb |
for repo in repos:
|
|
|
6e61fb |
name = repo['repo']
|
|
|
6e61fb |
priority = repo['priority']
|
|
|
6e61fb |
if name in names:
|
|
|
6e61fb |
raise DuplicateNameError(name)
|
|
|
6e61fb |
if priority in priorities:
|
|
|
6e61fb |
raise DuplicatePriorityError(priority)
|
|
|
6e61fb |
names.add(name)
|
|
|
6e61fb |
priorities.add(priority)
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def normalize_inheritance(inheritance):
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
Transform inheritance module argument input into the format returned by
|
|
|
6e61fb |
getInheritanceData(). Only includes supported fields (excluding child_id
|
|
|
6e61fb |
and parent_id), renames "parent" to "name", chooses correct defaults for
|
|
|
6e61fb |
missing fields, and performs some limited type correction for maxdepth and
|
|
|
6e61fb |
priority.
|
|
|
6e61fb |
|
|
|
6e61fb |
:param inheritance: list of inheritance dicts
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
normalized_inheritance = []
|
|
|
6e61fb |
|
|
|
6e61fb |
for rule in inheritance:
|
|
|
6e61fb |
# maxdepth: treat empty strings the same as None
|
|
|
6e61fb |
maxdepth = rule.get('maxdepth')
|
|
|
6e61fb |
if maxdepth == '':
|
|
|
6e61fb |
maxdepth = None
|
|
|
6e61fb |
if isinstance(maxdepth, string_types):
|
|
|
6e61fb |
maxdepth = int(maxdepth)
|
|
|
6e61fb |
|
|
|
6e61fb |
normalized_inheritance.append(dict(
|
|
|
6e61fb |
# we don't know child_id yet
|
|
|
6e61fb |
intransitive=rule.get('intransitive', False),
|
|
|
6e61fb |
maxdepth=maxdepth,
|
|
|
6e61fb |
name=rule['parent'],
|
|
|
6e61fb |
noconfig=rule.get('noconfig', False),
|
|
|
6e61fb |
# we don't know parent_id yet
|
|
|
6e61fb |
pkg_filter=rule.get('pkg_filter', ''),
|
|
|
6e61fb |
priority=int(rule['priority']),
|
|
|
6e61fb |
))
|
|
|
6e61fb |
|
|
|
6e61fb |
return sorted(normalized_inheritance, key=lambda i: i['priority'])
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def ensure_inheritance(session, tag_name, tag_id, check_mode, inheritance):
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
Ensure that these inheritance rules are configured on this Koji tag.
|
|
|
6e61fb |
|
|
|
6e61fb |
:param session: Koji client session
|
|
|
6e61fb |
:param str tag_name: Koji tag name
|
|
|
6e61fb |
:param int tag_id: Koji tag ID
|
|
|
6e61fb |
:param bool check_mode: don't make any changes
|
|
|
6e61fb |
:param list inheritance: ensure these rules are set, and no others
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
result = {'changed': False, 'stdout_lines': []}
|
|
|
6e61fb |
|
|
|
6e61fb |
# resolve parent tag IDs
|
|
|
6e61fb |
rules = []
|
|
|
6e61fb |
for rule in normalize_inheritance(inheritance):
|
|
|
6e61fb |
parent_name = rule['name']
|
|
|
6e61fb |
parent_taginfo = session.getTag(parent_name)
|
|
|
6e61fb |
if not parent_taginfo:
|
|
|
6e61fb |
msg = "parent tag '%s' not found" % parent_name
|
|
|
6e61fb |
if check_mode:
|
|
|
6e61fb |
result['stdout_lines'].append(msg)
|
|
|
6e61fb |
# spoof to allow continuation
|
|
|
6e61fb |
parent_taginfo = {'id': 0}
|
|
|
6e61fb |
else:
|
|
|
6e61fb |
raise ValueError(msg)
|
|
|
6e61fb |
parent_id = parent_taginfo['id']
|
|
|
6e61fb |
rules.append(dict(rule, child_id=tag_id, parent_id=parent_id))
|
|
|
6e61fb |
|
|
|
6e61fb |
current_inheritance = session.getInheritanceData(tag_name)
|
|
|
6e61fb |
if current_inheritance != rules:
|
|
|
6e61fb |
result['stdout_lines'].extend(
|
|
|
6e61fb |
('current inheritance:',)
|
|
|
6e61fb |
+ common_koji.describe_inheritance(current_inheritance)
|
|
|
6e61fb |
+ ('new inheritance:',)
|
|
|
6e61fb |
+ common_koji.describe_inheritance(rules))
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
session.setInheritanceData(tag_name, rules, clear=True)
|
|
|
6e61fb |
return result
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def ensure_external_repos(session, tag_name, check_mode, repos):
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
Ensure that these external repos are configured on this Koji tag.
|
|
|
6e61fb |
|
|
|
6e61fb |
:param session: Koji client session
|
|
|
6e61fb |
:param str tag_name: Koji tag name
|
|
|
6e61fb |
:param bool check_mode: don't make any changes
|
|
|
6e61fb |
:param list repos: ensure these external repos are set, and no others.
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
result = {'changed': False, 'stdout_lines': []}
|
|
|
6e61fb |
validate_repos(repos)
|
|
|
6e61fb |
current_repo_list = session.getTagExternalRepos(tag_name)
|
|
|
6e61fb |
current = {repo['external_repo_name']: repo for repo in current_repo_list}
|
|
|
6e61fb |
current_priorities = {
|
|
|
6e61fb |
str(repo['priority']): repo for repo in current_repo_list
|
|
|
6e61fb |
}
|
|
|
6e61fb |
for repo in sorted(repos, key=lambda r: r['priority']):
|
|
|
6e61fb |
repo_name = repo['repo']
|
|
|
6e61fb |
repo_priority = repo['priority']
|
|
|
6e61fb |
if repo_name in current:
|
|
|
6e61fb |
# The repo is present for this tag.
|
|
|
6e61fb |
# Now ensure the priority is correct.
|
|
|
6e61fb |
if repo_priority == current[repo_name]['priority']:
|
|
|
6e61fb |
continue
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
msg = 'set %s repo priority to %i' % (repo_name, repo_priority)
|
|
|
6e61fb |
result['stdout_lines'].append(msg)
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
session.editTagExternalRepo(tag_name, repo_name, repo_priority)
|
|
|
6e61fb |
continue
|
|
|
6e61fb |
elif str(repo_priority) in current_priorities:
|
|
|
6e61fb |
# No need to check for name equivalence here; it would already
|
|
|
6e61fb |
# have happened
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
msg = 'set repo at priority %i to %s' % (repo_priority, repo_name)
|
|
|
6e61fb |
result['stdout_lines'].append(msg)
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
same_priority_repo = current_priorities.get(
|
|
|
6e61fb |
str(repo_priority)).get('external_repo_name')
|
|
|
6e61fb |
session.removeExternalRepoFromTag(tag_name, same_priority_repo)
|
|
|
6e61fb |
session.addExternalRepoToTag(
|
|
|
6e61fb |
tag_name, repo_name, repo_priority)
|
|
|
6e61fb |
# Prevent duplicate attempts
|
|
|
6e61fb |
del current_priorities[str(repo_priority)]
|
|
|
6e61fb |
continue
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
msg = 'add %s external repo to %s' % (repo_name, tag_name)
|
|
|
6e61fb |
result['stdout_lines'].append(msg)
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
session.addExternalRepoToTag(tag_name, repo_name, repo_priority)
|
|
|
6e61fb |
# Find the repos to remove from this tag.
|
|
|
6e61fb |
repo_names = [repo['repo'] for repo in repos]
|
|
|
6e61fb |
current_names = current.keys()
|
|
|
6e61fb |
repos_to_remove = set(current_names) - set(repo_names)
|
|
|
6e61fb |
for repo_name in repos_to_remove:
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
msg = 'removed %s repo from %s tag' % (repo_name, tag_name)
|
|
|
6e61fb |
result['stdout_lines'].append(msg)
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
session.removeExternalRepoFromTag(tag_name, repo_name)
|
|
|
6e61fb |
return result
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def ensure_packages(session, tag_name, tag_id, check_mode, packages):
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
Ensure that these packages are configured on this Koji tag.
|
|
|
6e61fb |
|
|
|
6e61fb |
:param session: Koji client session
|
|
|
6e61fb |
:param str tag_name: Koji tag name
|
|
|
6e61fb |
:param int tag_id: Koji tag ID
|
|
|
6e61fb |
:param bool check_mode: don't make any changes
|
|
|
6e61fb |
:param dict packages: ensure these packages are set (?)
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
result = {'changed': False, 'stdout_lines': []}
|
|
|
6e61fb |
# Note: this in particular could really benefit from koji's
|
|
|
6e61fb |
# multicalls...
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
current_pkgs = session.listPackages(tagID=tag_id)
|
|
|
6e61fb |
current_names = set([pkg['package_name'] for pkg in current_pkgs])
|
|
|
6e61fb |
# Create a "current_owned" dict to compare with what's in Ansible.
|
|
|
6e61fb |
current_owned = defaultdict(set)
|
|
|
6e61fb |
for pkg in current_pkgs:
|
|
|
6e61fb |
owner = pkg['owner_name']
|
|
|
6e61fb |
pkg_name = pkg['package_name']
|
|
|
6e61fb |
current_owned[owner].add(pkg_name)
|
|
|
6e61fb |
for owner, owned in packages.items():
|
|
|
6e61fb |
for package in owned:
|
|
|
6e61fb |
if package not in current_names:
|
|
|
6e61fb |
# The package was missing from the tag entirely.
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
session.packageListAdd(tag_name, package, owner)
|
|
|
6e61fb |
result['stdout_lines'].append('added pkg %s' % package)
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
else:
|
|
|
6e61fb |
# The package is already in this tag.
|
|
|
6e61fb |
# Verify ownership.
|
|
|
6e61fb |
if package not in current_owned.get(owner, []):
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
session.packageListSetOwner(tag_name, package, owner)
|
|
|
6e61fb |
result['stdout_lines'].append('set %s owner %s' %
|
|
|
6e61fb |
(package, owner))
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
# Delete any packages not in Ansible.
|
|
|
6e61fb |
all_names = [name for names in packages.values() for name in names]
|
|
|
6e61fb |
delete_names = set(current_names) - set(all_names)
|
|
|
6e61fb |
for package in delete_names:
|
|
|
6e61fb |
result['stdout_lines'].append('remove pkg %s' % package)
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
session.packageListRemove(tag_name, package, owner)
|
|
|
6e61fb |
return result
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def ensure_groups(session, tag_id, check_mode, desired_groups):
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
Ensure that these groups are configured on this Koji tag.
|
|
|
6e61fb |
|
|
|
6e61fb |
:param session: Koji client session
|
|
|
6e61fb |
:param int tag_id: Koji tag ID
|
|
|
6e61fb |
:param bool check_mode: don't make any changes
|
|
|
6e61fb |
:param dict desired_groups: ensure these groups are set (?)
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
result = {'changed': False, 'stdout_lines': []}
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
current_groups = session.getTagGroups(tag_id)
|
|
|
6e61fb |
for group in current_groups:
|
|
|
6e61fb |
if group['tag_id'] == tag_id and group['name'] not in desired_groups:
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
session.groupListRemove(tag_id, group['name'])
|
|
|
6e61fb |
result['stdout_lines'].append('removed group %s' % group['name'])
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
for group_name, desired_pkgs in desired_groups.items():
|
|
|
6e61fb |
for group in current_groups:
|
|
|
6e61fb |
if group['name'] == group_name:
|
|
|
6e61fb |
current_pkgs = {entry['package']: entry['tag_id']
|
|
|
6e61fb |
for entry in group['packagelist']}
|
|
|
6e61fb |
break
|
|
|
6e61fb |
else:
|
|
|
6e61fb |
current_pkgs = {}
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
session.groupListAdd(tag_id, group_name)
|
|
|
6e61fb |
result['stdout_lines'].append('added group %s' % group_name)
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
|
|
|
6e61fb |
for package, pkg_tag_id in current_pkgs.items():
|
|
|
6e61fb |
if pkg_tag_id == tag_id and package not in desired_pkgs:
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
session.groupPackageListRemove(tag_id, group_name, package)
|
|
|
6e61fb |
result['stdout_lines'].append('removed pkg %s from group %s' % (package, group_name))
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
for package in desired_pkgs:
|
|
|
6e61fb |
if package not in current_pkgs:
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
session.groupPackageListAdd(tag_id, group_name, package)
|
|
|
6e61fb |
result['stdout_lines'].append('added pkg %s to group %s' % (package, group_name))
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
return result
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def compound_parameter_present(param_name, param, expected_type):
|
|
|
6e61fb |
if param not in (None, ''):
|
|
|
6e61fb |
if not isinstance(param, expected_type):
|
|
|
6e61fb |
raise ValueError(param_name + ' must be a '
|
|
|
6e61fb |
+ expected_type.__class__.__name__
|
|
|
6e61fb |
+ ', not a ' + param.__class__.__name__)
|
|
|
6e61fb |
return True
|
|
|
6e61fb |
return False
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def ensure_tag(session, name, check_mode, inheritance, external_repos,
|
|
|
6e61fb |
packages, groups, **kwargs):
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
Ensure that this tag exists in Koji.
|
|
|
6e61fb |
|
|
|
6e61fb |
:param session: Koji client session
|
|
|
6e61fb |
:param name: Koji tag name
|
|
|
6e61fb |
:param check_mode: don't make any changes
|
|
|
6e61fb |
:param inheritance: Koji tag inheritance settings. These will be translated
|
|
|
6e61fb |
for Koji's setInheritanceData RPC.
|
|
|
6e61fb |
:param external_repos: Koji external repos to set for this tag.
|
|
|
6e61fb |
:param packages: dict of packages to add ("whitelist") for this tag.
|
|
|
6e61fb |
If this is an empty dict, we don't touch the package list
|
|
|
6e61fb |
for this tag.
|
|
|
6e61fb |
:param groups: dict of comps groups to set for this tag.
|
|
|
6e61fb |
:param **kwargs: Pass remaining kwargs directly into Koji's createTag and
|
|
|
6e61fb |
editTag2 RPCs.
|
|
|
6e61fb |
"""
|
|
|
6e61fb |
taginfo = session.getTag(name)
|
|
|
6e61fb |
result = {'changed': False, 'stdout_lines': []}
|
|
|
6e61fb |
if not taginfo:
|
|
|
6e61fb |
if check_mode:
|
|
|
6e61fb |
result['stdout_lines'].append('would create tag %s' % name)
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
return result
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
if 'perm' in kwargs and kwargs['perm']:
|
|
|
6e61fb |
kwargs['perm'] = common_koji.get_perm_id(session, kwargs['perm'])
|
|
|
6e61fb |
id_ = session.createTag(name, parent=None, **kwargs)
|
|
|
6e61fb |
result['stdout_lines'].append('created tag id %d' % id_)
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
taginfo = {'id': id_} # populate for inheritance management below
|
|
|
6e61fb |
else:
|
|
|
6e61fb |
# The tag name already exists. Ensure all the parameters are set.
|
|
|
6e61fb |
edits = {}
|
|
|
6e61fb |
edit_log = []
|
|
|
6e61fb |
for key, value in kwargs.items():
|
|
|
6e61fb |
if taginfo[key] != value and value is not None:
|
|
|
6e61fb |
edits[key] = value
|
|
|
6e61fb |
edit_log.append('%s: changed %s from "%s" to "%s"'
|
|
|
6e61fb |
% (name, key, taginfo[key], value))
|
|
|
6e61fb |
# Find out which "extra" items we must explicitly remove
|
|
|
6e61fb |
# ("remove_extra" argument to editTag2).
|
|
|
6e61fb |
if 'extra' in kwargs and kwargs['extra'] is not None:
|
|
|
6e61fb |
for key in taginfo['extra']:
|
|
|
6e61fb |
if key not in kwargs['extra']:
|
|
|
6e61fb |
if 'remove_extra' not in edits:
|
|
|
6e61fb |
edits['remove_extra'] = []
|
|
|
6e61fb |
edits['remove_extra'].append(key)
|
|
|
6e61fb |
if 'remove_extra' in edits:
|
|
|
6e61fb |
edit_log.append('%s: remove extra fields "%s"'
|
|
|
6e61fb |
% (name, '", "'.join(edits['remove_extra'])))
|
|
|
6e61fb |
if edits:
|
|
|
6e61fb |
result['stdout_lines'].extend(edit_log)
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
session.editTag2(name, **edits)
|
|
|
6e61fb |
|
|
|
6e61fb |
# Ensure inheritance rules are all set.
|
|
|
6e61fb |
if compound_parameter_present('inheritance', inheritance, list):
|
|
|
6e61fb |
inheritance_result = ensure_inheritance(session, name, taginfo['id'],
|
|
|
6e61fb |
check_mode, inheritance)
|
|
|
6e61fb |
if inheritance_result['changed']:
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
result['stdout_lines'].extend(inheritance_result['stdout_lines'])
|
|
|
6e61fb |
|
|
|
6e61fb |
# Ensure external repos.
|
|
|
6e61fb |
if compound_parameter_present('external_repos', external_repos, list):
|
|
|
6e61fb |
repos_result = ensure_external_repos(session, name, check_mode,
|
|
|
6e61fb |
external_repos)
|
|
|
6e61fb |
if repos_result['changed']:
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
result['stdout_lines'].extend(repos_result['stdout_lines'])
|
|
|
6e61fb |
|
|
|
6e61fb |
# Ensure package list.
|
|
|
6e61fb |
if compound_parameter_present('packages', packages, dict):
|
|
|
6e61fb |
packages_result = ensure_packages(session, name, taginfo['id'],
|
|
|
6e61fb |
check_mode, packages)
|
|
|
6e61fb |
if packages_result['changed']:
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
result['stdout_lines'].extend(packages_result['stdout_lines'])
|
|
|
6e61fb |
|
|
|
6e61fb |
# Ensure group list.
|
|
|
6e61fb |
if compound_parameter_present('groups', groups, dict):
|
|
|
6e61fb |
groups_result = ensure_groups(session, taginfo['id'],
|
|
|
6e61fb |
check_mode, groups)
|
|
|
6e61fb |
if groups_result['changed']:
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
result['stdout_lines'].extend(groups_result['stdout_lines'])
|
|
|
6e61fb |
|
|
|
6e61fb |
return result
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def delete_tag(session, name, check_mode):
|
|
|
6e61fb |
""" Ensure that this tag is deleted from Koji. """
|
|
|
6e61fb |
taginfo = session.getTag(name)
|
|
|
6e61fb |
result = dict(
|
|
|
6e61fb |
stdout='',
|
|
|
6e61fb |
changed=False,
|
|
|
6e61fb |
)
|
|
|
6e61fb |
if taginfo:
|
|
|
6e61fb |
result['stdout'] = 'deleted tag %d' % taginfo['id']
|
|
|
6e61fb |
result['changed'] = True
|
|
|
6e61fb |
if not check_mode:
|
|
|
6e61fb |
common_koji.ensure_logged_in(session)
|
|
|
6e61fb |
session.deleteTag(name)
|
|
|
6e61fb |
return result
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def run_module():
|
|
|
6e61fb |
module_args = dict(
|
|
|
6e61fb |
koji=dict(type='str', required=False),
|
|
|
6e61fb |
name=dict(type='str', required=True),
|
|
|
6e61fb |
state=dict(type='str', choices=[
|
|
|
6e61fb |
'present', 'absent'], required=False, default='present'),
|
|
|
6e61fb |
inheritance=dict(type='raw', required=False, default=None),
|
|
|
6e61fb |
external_repos=dict(type='raw', required=False, default=None),
|
|
|
6e61fb |
packages=dict(type='raw', required=False, default=None),
|
|
|
6e61fb |
groups=dict(type='raw', required=False, default=None),
|
|
|
6e61fb |
arches=dict(type='str', required=False, default=None),
|
|
|
6e61fb |
perm=dict(type='str', required=False, default=None),
|
|
|
6e61fb |
locked=dict(type='bool', required=False, default=False),
|
|
|
6e61fb |
maven_support=dict(type='bool', required=False, default=False),
|
|
|
6e61fb |
maven_include_all=dict(type='bool', required=False, default=False),
|
|
|
6e61fb |
extra=dict(type='dict', required=False, default=None),
|
|
|
6e61fb |
)
|
|
|
6e61fb |
module = AnsibleModule(
|
|
|
6e61fb |
argument_spec=module_args,
|
|
|
6e61fb |
supports_check_mode=True
|
|
|
6e61fb |
)
|
|
|
6e61fb |
|
|
|
6e61fb |
if not common_koji.HAS_KOJI:
|
|
|
6e61fb |
module.fail_json(msg='koji is required for this module')
|
|
|
6e61fb |
|
|
|
6e61fb |
check_mode = module.check_mode
|
|
|
6e61fb |
params = module.params
|
|
|
6e61fb |
profile = params['koji']
|
|
|
6e61fb |
name = params['name']
|
|
|
6e61fb |
state = params['state']
|
|
|
6e61fb |
|
|
|
6e61fb |
session = common_koji.get_session(profile)
|
|
|
6e61fb |
|
|
|
6e61fb |
if state == 'present':
|
|
|
6e61fb |
result = ensure_tag(session, name,
|
|
|
6e61fb |
check_mode,
|
|
|
6e61fb |
inheritance=params['inheritance'],
|
|
|
6e61fb |
external_repos=params['external_repos'],
|
|
|
6e61fb |
packages=params['packages'],
|
|
|
6e61fb |
groups=params['groups'],
|
|
|
6e61fb |
arches=params['arches'],
|
|
|
6e61fb |
perm=params['perm'] or None,
|
|
|
6e61fb |
locked=params['locked'],
|
|
|
6e61fb |
maven_support=params['maven_support'],
|
|
|
6e61fb |
maven_include_all=params['maven_include_all'],
|
|
|
6e61fb |
extra=params['extra'])
|
|
|
6e61fb |
elif state == 'absent':
|
|
|
6e61fb |
result = delete_tag(session, name, check_mode)
|
|
|
6e61fb |
|
|
|
6e61fb |
module.exit_json(**result)
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
def main():
|
|
|
6e61fb |
run_module()
|
|
|
6e61fb |
|
|
|
6e61fb |
|
|
|
6e61fb |
if __name__ == '__main__':
|
|
|
6e61fb |
main()
|