Merge "Add tripleo_dnf_stream Ansible module." into stable/ussuri
This commit is contained in:
commit
42f01c6e75
|
@ -0,0 +1,264 @@
|
|||
# Copyright 2021 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: tripleo_dnf_stream
|
||||
short_description: Enable or disable a set of DNF stream modules if available.
|
||||
description:
|
||||
- "Enables or disables one or more I(dnf) module streams. If no stream is being
|
||||
specified, the default stream will be enabled/disabled."
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- "A module name to enable or disable, like C(container-tools:3.0).
|
||||
If no stream or profile is specified then the defaults will be enabled
|
||||
To handle multiple I(dnf) modules this parameter can accept a comma
|
||||
separated string or a list of module names with their streams.
|
||||
Passing the profile in this parameter won't have any impact as the
|
||||
module only enables or disables the stream, it doesn't install/uninstall
|
||||
packages."
|
||||
required: true
|
||||
type: list
|
||||
elements: str
|
||||
state:
|
||||
description:
|
||||
- "Whether to enable or disable a module. After the task is executed only
|
||||
the module will change, there is no packages synchronization performed.
|
||||
To do so, please check the I(dnf) Ansible module."
|
||||
default: 'enabled'
|
||||
required: false
|
||||
type: str
|
||||
choices: ['enabled', 'disabled']
|
||||
|
||||
author:
|
||||
- Jose Luis Franco Arza (@jfrancoa)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- hosts: dbservers
|
||||
tasks:
|
||||
- name: Enable container-tools:3.0 stream module
|
||||
tripleo_dnf_stream:
|
||||
name: container-tools:3.0
|
||||
state: enabled
|
||||
- name: Disable container-tools:3.0 stream module
|
||||
tripleo_dnf_stream:
|
||||
name: container-tools:3.0
|
||||
state: disabled
|
||||
- name: Enable nginx, php:7.4 and python36:36
|
||||
tripleo_dnf_stream:
|
||||
name:
|
||||
- nginx
|
||||
- php:7.4
|
||||
- python36:3.6
|
||||
- name: Update packages
|
||||
dnf:
|
||||
name: *
|
||||
state: latest
|
||||
'''
|
||||
|
||||
import sys
|
||||
|
||||
try:
|
||||
import dnf
|
||||
import dnf.cli
|
||||
import dnf.const
|
||||
import dnf.exceptions
|
||||
import dnf.subject
|
||||
import dnf.util
|
||||
HAS_DNF = True
|
||||
except ImportError:
|
||||
HAS_DNF = False
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
from yaml import safe_load as yaml_safe_load
|
||||
|
||||
|
||||
class DnfModule():
|
||||
"""
|
||||
DNF Ansible module back-end implementation
|
||||
"""
|
||||
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
|
||||
self.name = self.module.params['name']
|
||||
self.state = self.module.params['state']
|
||||
|
||||
self._ensure_dnf()
|
||||
|
||||
try:
|
||||
dnf.base.WITH_MODULES
|
||||
except AttributeError:
|
||||
self.module.fail_json(
|
||||
msg="DNF modules are not supported.",
|
||||
results=[],
|
||||
)
|
||||
|
||||
def _ensure_dnf(self):
|
||||
if not HAS_DNF:
|
||||
self.module.fail_json(
|
||||
msg="Could not import the dnf python module using {0} ({1}). "
|
||||
"Please install `python3-dnf` package or ensure you have specified the "
|
||||
"correct ansible_python_interpreter.".format(sys.executable, sys.version.replace('\n', '')),
|
||||
results=[],
|
||||
)
|
||||
|
||||
def _base(self):
|
||||
"""Return a fully configured dnf Base object."""
|
||||
base = dnf.Base()
|
||||
base.read_all_repos()
|
||||
base.fill_sack()
|
||||
try:
|
||||
# this method has been supported in dnf-4.2.17-6 or later
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1788212
|
||||
base.setup_loggers()
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
base.init_plugins()
|
||||
base.pre_configure_plugins()
|
||||
except AttributeError:
|
||||
pass # older versions of dnf didn't require this and don't have these methods
|
||||
try:
|
||||
base.configure_plugins()
|
||||
except AttributeError:
|
||||
pass # older versions of dnf didn't require this and don't have these methods
|
||||
|
||||
return base
|
||||
|
||||
def _is_module_available(self, module_spec):
|
||||
module_spec = module_spec.strip()
|
||||
module_list, nsv = self.module_base._get_modules(module_spec)
|
||||
|
||||
if nsv:
|
||||
return True, nsv
|
||||
else:
|
||||
return False, None
|
||||
|
||||
def _is_module_enabled(self, module_nsv):
|
||||
enabled_streams = self.base._moduleContainer.getEnabledStream(module_nsv.name)
|
||||
|
||||
if enabled_streams:
|
||||
if module_nsv.stream:
|
||||
if module_nsv.stream in enabled_streams:
|
||||
return True # The provided stream was found
|
||||
else:
|
||||
return False # The provided stream was not found
|
||||
else:
|
||||
return True # No stream provided, but module found
|
||||
|
||||
def ensure(self):
|
||||
response = {
|
||||
'msg': "",
|
||||
'changed': False,
|
||||
'results': [],
|
||||
'rc': 0
|
||||
}
|
||||
|
||||
# Accumulate failures. Package management modules install what they can
|
||||
# and fail with a message about what they can't.
|
||||
failure_response = {
|
||||
'msg': "",
|
||||
'failures': [],
|
||||
'results': [],
|
||||
'rc': 1
|
||||
}
|
||||
|
||||
if self.state == 'enabled':
|
||||
for module in self.name:
|
||||
try:
|
||||
module_found, nsv = self._is_module_available(module)
|
||||
if module_found:
|
||||
if self._is_module_enabled(nsv):
|
||||
response['results'].append("Module {0} already enabled.".format(module))
|
||||
self.module_base.enable([module])
|
||||
else:
|
||||
failure_response['failures'].append("Module {0} is not available in the system.".format(module))
|
||||
except dnf.exceptions.MarkingErrors as e:
|
||||
failure_response['failures'].append(' '.join((module, to_native(e))))
|
||||
|
||||
else:
|
||||
# state = 'disabled'
|
||||
for module in self.name:
|
||||
try:
|
||||
module_found, nsv = self._is_module_available(module)
|
||||
if module_found:
|
||||
if not self._is_module_enabled(nsv):
|
||||
response['results'].append("Module {0} already disabled.".format(module))
|
||||
self.module_base.disable([module])
|
||||
self.module_base.reset([module])
|
||||
else:
|
||||
# If the module is not available move on
|
||||
response['results'].append("Module {0} is not available in the system".format(module))
|
||||
except dnf.exceptions.MarkingErrors as e:
|
||||
failure_response['failures'].append(' '.join((module, to_native(e))))
|
||||
|
||||
try:
|
||||
if failure_response['failures']:
|
||||
failure_response['msg'] = 'Failed to manage some of the specified modules'
|
||||
self.module.fail_json(**failure_response)
|
||||
|
||||
# Perform the transaction if no failures found
|
||||
self.base.do_transaction()
|
||||
self.module.exit_json(**response)
|
||||
except dnf.exceptions.Error as e:
|
||||
failure_response['msg'] = "Unknown Error occured: {0}".format(to_native(e))
|
||||
self.module.fail_json(**failure_response)
|
||||
|
||||
response['changed'] = True
|
||||
|
||||
def run(self):
|
||||
"""The main function."""
|
||||
|
||||
# Note: base takes a long time to run so we want to check for failure
|
||||
# before running it.
|
||||
if not dnf.util.am_i_root():
|
||||
self.module.fail_json(
|
||||
msg="This command has to be run under the root user.",
|
||||
results=[],
|
||||
)
|
||||
|
||||
self.base = self._base()
|
||||
|
||||
self.module_base = dnf.module.module_base.ModuleBase(self.base)
|
||||
|
||||
self.ensure()
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=yaml_safe_load(DOCUMENTATION)['options'],
|
||||
supports_check_mode=False,
|
||||
)
|
||||
|
||||
module_implementation = DnfModule(module)
|
||||
try:
|
||||
module_implementation.run()
|
||||
except dnf.exceptions.RepoError as de:
|
||||
module.fail_json(
|
||||
msg="Failed to synchronize repodata: {0}".format(to_native(de)),
|
||||
rc=1,
|
||||
results=[],
|
||||
changed=False
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,140 @@
|
|||
---
|
||||
- name: Converge
|
||||
hosts: all
|
||||
become: true
|
||||
tasks:
|
||||
- name: List available modules at test start for debugging purposes
|
||||
command: dnf module list
|
||||
register: module_list
|
||||
- debug:
|
||||
msg: "{{ module_list.stdout_lines }}"
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
PREPARE: enable maven:3.5
|
||||
================================================================"
|
||||
- name: Make sure the module is removed before starting
|
||||
command: dnf module -C -y remove maven:3.5
|
||||
- name: Disable the module
|
||||
command: dnf module -C -y reset maven:3.5
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
START: enable maven:3.5
|
||||
================================================================"
|
||||
- name: Enable maven:3.5 module
|
||||
tripleo_dnf_stream:
|
||||
name: "maven:3.5"
|
||||
state: enabled
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
VERIFY: enable maven:3.5
|
||||
================================================================"
|
||||
- name: Ensure the module got enabled
|
||||
shell: "dnf module -C -y list --enabled | grep 'maven\\s*3.5'"
|
||||
failed_when: false
|
||||
register: check_module
|
||||
- name: Fail if module not found enabled
|
||||
fail:
|
||||
msg: Module maven:3.5 not found
|
||||
when: check_module.rc != 0
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
PREPARE: change php:7.2 to php:7.3
|
||||
================================================================"
|
||||
- name: Make sure the module is enabled before starting
|
||||
command: dnf module -C -y reset php
|
||||
- name: Enable the module nginx (php has dependencies on nginx) and php
|
||||
command: "dnf module -y install {{ item }}"
|
||||
loop:
|
||||
- "nginx"
|
||||
- "php:7.2"
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
START: change php:7.2 to php:7.3
|
||||
================================================================"
|
||||
- name: Enable php:7.3 module
|
||||
tripleo_dnf_stream:
|
||||
name: "php:7.3"
|
||||
state: enabled
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
VERIFY: change php:7.2 to php:7.3
|
||||
================================================================"
|
||||
- name: Ensure the module got enabled
|
||||
shell: "dnf module -C -y list --enabled | grep 'php\\s*7.3'"
|
||||
failed_when: false
|
||||
register: check_module
|
||||
- name: Fail if module not found enabled
|
||||
fail:
|
||||
msg: Module php:7.3 not found
|
||||
when: check_module.rc != 0
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
PREPARE: enable and disable multiple streams
|
||||
================================================================"
|
||||
- name: Make sure the module is disabled before starting
|
||||
command: "dnf module -C -y remove nodejs:12 javapackages-runtime:201801"
|
||||
- name: Disable the module
|
||||
command: "dnf module -C -y reset nodejs javapackages-runtime"
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
START 1: enable multiple streams
|
||||
================================================================"
|
||||
- name: Enable nodejs:12 and javapackages-runtime:201801 module
|
||||
tripleo_dnf_stream:
|
||||
name:
|
||||
- "nodejs:12"
|
||||
- "javapackages-runtime:201801"
|
||||
state: enabled
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
VERIFY 1: enable multiple streams
|
||||
================================================================"
|
||||
- name: Ensure the module got enabled
|
||||
shell: "dnf module -C -y list --enabled | grep '{{ item.split(\":\")[0] }}\\s*{{ item.split(\":\")[1] }}'"
|
||||
failed_when: false
|
||||
register: check_module
|
||||
loop:
|
||||
- "nodejs:12"
|
||||
- "javapackages-runtime:201801"
|
||||
- name: Fail if module not found enabled
|
||||
fail:
|
||||
msg: "Module {{ item.item }} not found"
|
||||
when: item.rc != 0
|
||||
loop: "{{ check_module.results }}"
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
START 2: disable multiple streams
|
||||
================================================================"
|
||||
- name: Disable all enabled modules
|
||||
tripleo_dnf_stream:
|
||||
name:
|
||||
- "nodejs:12"
|
||||
- "javapackages-runtime:201801"
|
||||
state: disabled
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
VERIFY 2: disable multiple streams
|
||||
================================================================"
|
||||
- name: Ensure all modules got disabled
|
||||
shell: "dnf module -C -y list --enabled | grep '{{ item.split(\":\")[0] }}\\s*{{ item.split(\":\")[1] }}'"
|
||||
failed_when: false
|
||||
register: check_module
|
||||
loop:
|
||||
- "nodejs:12"
|
||||
- "javapackages-runtime:201801"
|
||||
- name: Fail if module found enabled
|
||||
fail:
|
||||
msg: "Module {{ item.item }} found enabled when it shouldn't"
|
||||
when: item.rc == 0
|
||||
loop: "{{ check_module.results }}"
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
driver:
|
||||
name: podman
|
||||
|
||||
log: true
|
||||
|
||||
platforms:
|
||||
- name: ubi8
|
||||
hostname: ubi8
|
||||
image: ubi8/ubi-init
|
||||
registry:
|
||||
url: registry.access.redhat.com
|
||||
dockerfile: Dockerfile
|
||||
pkg_extras: python*setuptools
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
- /etc/ci/mirror_info.sh:/etc/ci/mirror_info.sh:ro
|
||||
- /etc/pki/rpm-gpg:/etc/pki/rpm-gpg
|
||||
- /etc/dnf/vars:/etc/dnf/vars
|
||||
privileged: true
|
||||
environment: &env
|
||||
http_proxy: "{{ lookup('env', 'http_proxy') }}"
|
||||
https_proxy: "{{ lookup('env', 'https_proxy') }}"
|
||||
ulimits: &ulimit
|
||||
- host
|
||||
|
||||
provisioner:
|
||||
name: ansible
|
||||
inventory:
|
||||
hosts:
|
||||
all:
|
||||
hosts:
|
||||
ubi8:
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
log: true
|
||||
env:
|
||||
ANSIBLE_STDOUT_CALLBACK: yaml
|
||||
|
||||
scenario:
|
||||
name: tripleo_dnf_stream
|
||||
test_sequence:
|
||||
- destroy
|
||||
- create
|
||||
- prepare
|
||||
- converge
|
||||
- verify
|
||||
- destroy
|
||||
|
||||
verifier:
|
||||
name: testinfra
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
# Copyright 2019 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
- name: Prepare
|
||||
hosts: all
|
||||
roles:
|
||||
- role: test_deps
|
||||
tasks:
|
||||
- debug:
|
||||
msg: |
|
||||
"================================================================
|
||||
STARTING TEST tripleo_dnf_stream
|
||||
================================================================"
|
|
@ -557,6 +557,7 @@
|
|||
- ^tripleo_ansible/ansible_plugins/modules/tripleo_container_configs.py
|
||||
- ^tripleo_ansible/ansible_plugins/modules/tripleo_container_config_scripts.py
|
||||
- ^tripleo_ansible/ansible_plugins/modules/tripleo_os_net_config.py
|
||||
- ^tripleo_ansible/ansible_plugins/modules/tripleo_dnf_stream.py
|
||||
- ^tripleo_ansible/ansible_plugins/strategy/.*
|
||||
- ^tox.ini
|
||||
name: tripleo-ansible-centos-8-molecule-tripleo-modules
|
||||
|
|
Loading…
Reference in New Issue