Merge "Improvements to yum-config module"
This commit is contained in:
commit
de3736a739
|
@ -13,34 +13,47 @@
|
||||||
register: result
|
register: result
|
||||||
failed_when: result is success
|
failed_when: result is success
|
||||||
|
|
||||||
- name: "Disable one of the system repos"
|
- name: "Test disable system repo"
|
||||||
become: true
|
become: true
|
||||||
tripleo.repos.yum_config:
|
tripleo.repos.yum_config:
|
||||||
type: repo
|
type: repo
|
||||||
name: rt
|
name: "{{ 'rt' if (ansible_distribution_major_version is version(8, '>=')) else 'cr' }}"
|
||||||
file_path: /etc/yum.repos.d/CentOS-Stream-RealTime.repo
|
|
||||||
enabled: false
|
enabled: false
|
||||||
tags:
|
tags:
|
||||||
# TODO: fix yum_config to correctly report changed state and uncomment
|
# TODO: fix yum_config to correctly report changed state and uncomment
|
||||||
# the line below which disables molecule idemptotence test.
|
# the line below which disables molecule idempotence test.
|
||||||
- molecule-idempotence-notest
|
- molecule-idempotence-notest
|
||||||
# TODO: code needs a fix to be compatible with CentOS-7
|
|
||||||
when: ansible_distribution_major_version is version(8, '>=')
|
|
||||||
|
|
||||||
- name: "Update yum_config global config"
|
- name: "Test create new repo file"
|
||||||
|
become: true
|
||||||
|
tripleo.repos.yum_config:
|
||||||
|
type: repo
|
||||||
|
name: "fakerepo"
|
||||||
|
# Keep it disabled to not affect any other test
|
||||||
|
enabled: false
|
||||||
|
file_path: "/etc/yum.repos.d/fake_repo.repo"
|
||||||
|
set_options:
|
||||||
|
baseurl: "http://fakemirror/fakerepo"
|
||||||
|
priority: "10"
|
||||||
|
gpgcheck: "0"
|
||||||
|
exclude: "fakepkg*"
|
||||||
|
tags:
|
||||||
|
# TODO: fix yum_config to correctly report changed state and uncomment
|
||||||
|
# the line below which disables molecule idempotence test.
|
||||||
|
- molecule-idempotence-notest
|
||||||
|
|
||||||
|
- name: "Test yum-config global config"
|
||||||
become: true
|
become: true
|
||||||
tripleo.repos.yum_config:
|
tripleo.repos.yum_config:
|
||||||
type: global
|
type: global
|
||||||
file_path: /etc/dnf/dnf.conf
|
file_path: "{{ '/etc/dnf/dnf.conf' if (ansible_distribution_major_version is version(8, '>=')) else '/etc/yum.conf' }}"
|
||||||
set_options:
|
set_options:
|
||||||
skip_if_unavailable: "False"
|
skip_if_unavailable: "False"
|
||||||
keepcache: "0"
|
fake_conf: "True"
|
||||||
tags:
|
tags:
|
||||||
# TODO: fix yum_config to correctly report changed state and uncomment
|
# TODO: fix yum_config to correctly report changed state and uncomment
|
||||||
# the line below which disables molecule idemptotence test.
|
# the line below which disables molecule idempotence test.
|
||||||
- molecule-idempotence-notest
|
- molecule-idempotence-notest
|
||||||
# TODO: code needs a fix to be compatible with CentOS-7
|
|
||||||
when: ansible_distribution_major_version is version(8, '>=')
|
|
||||||
|
|
||||||
- name: "Test yum_config enable-compose-repos"
|
- name: "Test yum_config enable-compose-repos"
|
||||||
become: true
|
become: true
|
||||||
|
|
|
@ -2,32 +2,33 @@
|
||||||
- name: Verify
|
- name: Verify
|
||||||
hosts: all
|
hosts: all
|
||||||
tasks:
|
tasks:
|
||||||
- name: Validate if RealTime repo is disabled
|
- name: Check if RT or CR repos are disabled
|
||||||
|
vars:
|
||||||
|
section_name: "{{ 'rt' if (ansible_distribution_major_version is version(8, '>=')) else 'cr' }}"
|
||||||
|
repo_path: /etc/yum.repos.d/CentOS-{{ 'Stream-RealTime' if (ansible_distribution_major_version is version(8, '>=')) else 'CR' }}.repo
|
||||||
include_tasks: assert_ini_key_value.yml
|
include_tasks: assert_ini_key_value.yml
|
||||||
with_items:
|
with_items:
|
||||||
- name: RealTime
|
- name: "{{ section_name|upper }}"
|
||||||
path: /etc/yum.repos.d/CentOS-Stream-RealTime.repo
|
path: "{{ repo_path }}"
|
||||||
section: rt
|
section: "{{ section_name }}"
|
||||||
key: enabled
|
key: enabled
|
||||||
value: "0"
|
value: "0"
|
||||||
# TODO: code needs a fix to be compatible with CentOS-7
|
|
||||||
when: ansible_distribution_major_version is version(8, '>=')
|
|
||||||
|
|
||||||
- name: Validate yum/dnf conf file
|
- name: Check if yum/dnf conf file was updated
|
||||||
|
vars:
|
||||||
|
conf_file_path: "{{ '/etc/dnf/dnf.conf' if (ansible_distribution_major_version is version(8, '>=')) else '/etc/yum.conf' }}"
|
||||||
include_tasks: assert_ini_key_value.yml
|
include_tasks: assert_ini_key_value.yml
|
||||||
with_items:
|
with_items:
|
||||||
- name: dnf.conf
|
- name: global_conf
|
||||||
path: /etc/dnf/dnf.conf
|
path: "{{ conf_file_path }}"
|
||||||
section: main
|
section: main
|
||||||
key: skip_if_unavailable
|
key: skip_if_unavailable
|
||||||
value: "False"
|
value: "False"
|
||||||
- name: dnf.conf
|
- name: global_conf
|
||||||
path: /etc/dnf/dnf.conf
|
path: "{{ conf_file_path }}"
|
||||||
section: main
|
section: main
|
||||||
key: keepcache
|
key: fake_conf
|
||||||
value: "0"
|
value: "True"
|
||||||
# TODO: code needs a fix to be compatible with CentOS-7
|
|
||||||
when: ansible_distribution_major_version is version(8, '>=')
|
|
||||||
|
|
||||||
- name: Validate compose repos outputs
|
- name: Validate compose repos outputs
|
||||||
include_tasks: verify_compose_repos.yml
|
include_tasks: verify_compose_repos.yml
|
||||||
|
|
|
@ -17,10 +17,9 @@ import argparse
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import tripleo_repos.yum_config.compose_repos as compose_repos
|
|
||||||
import tripleo_repos.yum_config.constants as const
|
import tripleo_repos.yum_config.constants as const
|
||||||
import tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
|
||||||
import tripleo_repos.yum_config.yum_config as cfg
|
import tripleo_repos.yum_config.yum_config as cfg
|
||||||
|
import tripleo_repos.yum_config.utils as utils
|
||||||
|
|
||||||
|
|
||||||
def options_to_dict(options):
|
def options_to_dict(options):
|
||||||
|
@ -39,6 +38,12 @@ def options_to_dict(options):
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
cfg.TripleOYumConfig.load_logging()
|
cfg.TripleOYumConfig.load_logging()
|
||||||
|
# Get release model and version
|
||||||
|
distro, major_version, __ = utils.get_distro_info()
|
||||||
|
py_version = sys.version_info.major
|
||||||
|
if py_version < 3:
|
||||||
|
logging.warning("Some operations will be disabled when running with "
|
||||||
|
"python 2.")
|
||||||
|
|
||||||
# Repo arguments
|
# Repo arguments
|
||||||
repo_args_parser = argparse.ArgumentParser(add_help=False)
|
repo_args_parser = argparse.ArgumentParser(add_help=False)
|
||||||
|
@ -47,6 +52,15 @@ def main():
|
||||||
help='name of the repo to be modified'
|
help='name of the repo to be modified'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
environment_parse = argparse.ArgumentParser(add_help=False)
|
||||||
|
environment_parse.add_argument(
|
||||||
|
'--environment-file',
|
||||||
|
dest='env_file',
|
||||||
|
default=None,
|
||||||
|
help=('path to an environment file to be read before creating repo '
|
||||||
|
'files'),
|
||||||
|
)
|
||||||
|
|
||||||
parser_enable_group = repo_args_parser.add_mutually_exclusive_group()
|
parser_enable_group = repo_args_parser.add_mutually_exclusive_group()
|
||||||
parser_enable_group.add_argument(
|
parser_enable_group.add_argument(
|
||||||
'--enable',
|
'--enable',
|
||||||
|
@ -171,24 +185,32 @@ def main():
|
||||||
# Subcommands
|
# Subcommands
|
||||||
subparsers.add_parser(
|
subparsers.add_parser(
|
||||||
'repo',
|
'repo',
|
||||||
parents=[common_parse, repo_args_parser, options_parse],
|
parents=[common_parse, environment_parse, repo_args_parser,
|
||||||
|
options_parse],
|
||||||
help='updates a yum repository options'
|
help='updates a yum repository options'
|
||||||
)
|
)
|
||||||
subparsers.add_parser(
|
|
||||||
'module',
|
|
||||||
parents=[dnf_module_parser],
|
|
||||||
help='updates yum module options'
|
|
||||||
)
|
|
||||||
subparsers.add_parser(
|
subparsers.add_parser(
|
||||||
'global',
|
'global',
|
||||||
parents=[common_parse, options_parse],
|
parents=[common_parse, environment_parse, options_parse],
|
||||||
help='updates global yum configuration options'
|
help='updates global yum configuration options'
|
||||||
)
|
)
|
||||||
subparsers.add_parser(
|
|
||||||
'enable-compose-repos',
|
if py_version >= 3:
|
||||||
parents=[compose_args_parser],
|
subparsers.add_parser(
|
||||||
help='enable CentOS compose repos based on an compose url.'
|
'enable-compose-repos',
|
||||||
)
|
parents=[compose_args_parser, environment_parse],
|
||||||
|
help='enable CentOS compose repos based on an compose url.'
|
||||||
|
)
|
||||||
|
|
||||||
|
for min_distro_ver in const.DNF_MODULE_MINIMAL_DISTRO_VERSIONS:
|
||||||
|
if (distro == min_distro_ver.get('distro') and int(
|
||||||
|
major_version) >= min_distro_ver.get('min_version')):
|
||||||
|
subparsers.add_parser(
|
||||||
|
'module',
|
||||||
|
parents=[dnf_module_parser],
|
||||||
|
help='updates yum module options'
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
args = main_parser.parse_args()
|
args = main_parser.parse_args()
|
||||||
if args.command is None:
|
if args.command is None:
|
||||||
|
@ -202,13 +224,14 @@ def main():
|
||||||
if args.command == 'repo':
|
if args.command == 'repo':
|
||||||
set_dict = options_to_dict(args.set_opts)
|
set_dict = options_to_dict(args.set_opts)
|
||||||
config_obj = cfg.TripleOYumRepoConfig(
|
config_obj = cfg.TripleOYumRepoConfig(
|
||||||
dir_path=args.config_dir_path)
|
dir_path=args.config_dir_path,
|
||||||
|
environment_file=args.env_file)
|
||||||
config_obj.update_section(args.name, set_dict,
|
config_obj.add_or_update_section(args.name, set_dict=set_dict,
|
||||||
file_path=args.config_file_path,
|
file_path=args.config_file_path,
|
||||||
enabled=args.enable)
|
enabled=args.enable)
|
||||||
|
|
||||||
elif args.command == 'module':
|
elif args.command == 'module':
|
||||||
|
import tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
||||||
dnf_mod_mgr = dnf_mgr.DnfModuleManager()
|
dnf_mod_mgr = dnf_mgr.DnfModuleManager()
|
||||||
dnf_method = getattr(dnf_mod_mgr, args.operation + "_module")
|
dnf_method = getattr(dnf_mod_mgr, args.operation + "_module")
|
||||||
dnf_method(args.name, stream=args.stream, profile=args.profile)
|
dnf_method(args.name, stream=args.stream, profile=args.profile)
|
||||||
|
@ -216,16 +239,19 @@ def main():
|
||||||
elif args.command == 'global':
|
elif args.command == 'global':
|
||||||
set_dict = options_to_dict(args.set_opts)
|
set_dict = options_to_dict(args.set_opts)
|
||||||
config_obj = cfg.TripleOYumGlobalConfig(
|
config_obj = cfg.TripleOYumGlobalConfig(
|
||||||
file_path=args.config_file_path)
|
file_path=args.config_file_path,
|
||||||
|
environment_file=args.env_file)
|
||||||
|
|
||||||
config_obj.update_section('main', set_dict)
|
config_obj.update_section('main', set_dict)
|
||||||
|
|
||||||
elif args.command == 'enable-compose-repos':
|
elif args.command == 'enable-compose-repos':
|
||||||
|
import tripleo_repos.yum_config.compose_repos as compose_repos
|
||||||
repo_obj = compose_repos.TripleOYumComposeRepoConfig(
|
repo_obj = compose_repos.TripleOYumComposeRepoConfig(
|
||||||
args.compose_url,
|
args.compose_url,
|
||||||
args.release,
|
args.release,
|
||||||
dir_path=args.config_dir_path,
|
dir_path=args.config_dir_path,
|
||||||
arch=args.arch)
|
arch=args.arch,
|
||||||
|
environment_file=args.env_file)
|
||||||
|
|
||||||
repo_obj.enable_compose_repos(variants=args.variants,
|
repo_obj.enable_compose_repos(variants=args.variants,
|
||||||
override_repos=args.disable_conflicting)
|
override_repos=args.disable_conflicting)
|
||||||
|
|
|
@ -18,8 +18,6 @@ import logging
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import urllib.parse
|
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
from .constants import (
|
from .constants import (
|
||||||
YUM_REPO_DIR,
|
YUM_REPO_DIR,
|
||||||
|
@ -44,7 +42,8 @@ __metaclass__ = type
|
||||||
class TripleOYumComposeRepoConfig(TripleOYumConfig):
|
class TripleOYumComposeRepoConfig(TripleOYumConfig):
|
||||||
"""Manages yum repo configuration files for CentOS Compose."""
|
"""Manages yum repo configuration files for CentOS Compose."""
|
||||||
|
|
||||||
def __init__(self, compose_url, release, dir_path=None, arch=None):
|
def __init__(self, compose_url, release, dir_path=None, arch=None,
|
||||||
|
environment_file=None):
|
||||||
conf_dir_path = dir_path or YUM_REPO_DIR
|
conf_dir_path = dir_path or YUM_REPO_DIR
|
||||||
self.arch = arch or 'x86_64'
|
self.arch = arch or 'x86_64'
|
||||||
|
|
||||||
|
@ -80,11 +79,13 @@ class TripleOYumComposeRepoConfig(TripleOYumConfig):
|
||||||
super(TripleOYumComposeRepoConfig, self).__init__(
|
super(TripleOYumComposeRepoConfig, self).__init__(
|
||||||
valid_options=YUM_REPO_SUPPORTED_OPTIONS,
|
valid_options=YUM_REPO_SUPPORTED_OPTIONS,
|
||||||
dir_path=conf_dir_path,
|
dir_path=conf_dir_path,
|
||||||
file_extension=YUM_REPO_FILE_EXTENSION)
|
file_extension=YUM_REPO_FILE_EXTENSION,
|
||||||
|
environment_file=environment_file)
|
||||||
|
|
||||||
def _get_compose_info(self):
|
def _get_compose_info(self):
|
||||||
"""Retrieve compose info for a provided compose-id url."""
|
"""Retrieve compose info for a provided compose-id url."""
|
||||||
# NOTE(dviroel): works for both centos 8 and 9
|
# NOTE(dviroel): works for both centos 8 and 9
|
||||||
|
import urllib.request
|
||||||
try:
|
try:
|
||||||
logging.debug("Retrieving compose info from url: %s",
|
logging.debug("Retrieving compose info from url: %s",
|
||||||
self.compose_info_url)
|
self.compose_info_url)
|
||||||
|
@ -179,7 +180,7 @@ class TripleOYumComposeRepoConfig(TripleOYumConfig):
|
||||||
def add_section(self, section, add_dict, file_path):
|
def add_section(self, section, add_dict, file_path):
|
||||||
# Create a new file if it does not exists
|
# Create a new file if it does not exists
|
||||||
if not os.path.isfile(file_path):
|
if not os.path.isfile(file_path):
|
||||||
with open(file_path, '+w'):
|
with open(file_path, 'w+'):
|
||||||
pass
|
pass
|
||||||
super(TripleOYumComposeRepoConfig, self).add_section(
|
super(TripleOYumComposeRepoConfig, self).add_section(
|
||||||
section, add_dict, file_path)
|
section, add_dict, file_path)
|
||||||
|
|
|
@ -19,14 +19,21 @@ List of options that can be updated for yum repo files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
YUM_REPO_SUPPORTED_OPTIONS = [
|
YUM_REPO_SUPPORTED_OPTIONS = [
|
||||||
'name',
|
|
||||||
'baseurl',
|
'baseurl',
|
||||||
|
'cost',
|
||||||
'enabled',
|
'enabled',
|
||||||
|
'exclude',
|
||||||
|
'excludepkgs',
|
||||||
'gpgcheck',
|
'gpgcheck',
|
||||||
'gpgkey',
|
'gpgkey',
|
||||||
'priority',
|
'includepkgs',
|
||||||
'exclude',
|
'metalink',
|
||||||
|
'mirrorlist',
|
||||||
|
'module_hotfixes',
|
||||||
|
'name',
|
||||||
|
'priority'
|
||||||
]
|
]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -68,3 +75,12 @@ COMPOSE_REPOS_INFO_PATH = {
|
||||||
"centos-stream-8": "metadata/composeinfo.json",
|
"centos-stream-8": "metadata/composeinfo.json",
|
||||||
"centos-stream-9": "metadata/composeinfo.json",
|
"centos-stream-9": "metadata/composeinfo.json",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
DNF Manager constants
|
||||||
|
"""
|
||||||
|
DNF_MODULE_MINIMAL_DISTRO_VERSIONS = [
|
||||||
|
{'distro': 'centos', 'min_version': 8},
|
||||||
|
{'distro': 'rhel', 'min_version': 8},
|
||||||
|
{'distro': 'fedora', 'min_version': 22},
|
||||||
|
]
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Copyright 2021 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(dviroel): Merge in a utils file when refactoring tripleo-repos.
|
||||||
|
def get_distro_info():
|
||||||
|
"""Get distro info from os-release file.
|
||||||
|
|
||||||
|
:return: distro_id, distro_major_version_id and distro_name
|
||||||
|
"""
|
||||||
|
if not os.path.exists('/etc/os-release'):
|
||||||
|
return platform.system(), 'unknown', 'unknown'
|
||||||
|
|
||||||
|
output = subprocess.Popen(
|
||||||
|
'source /etc/os-release && echo -e -n "$ID\n$VERSION_ID\n$NAME"',
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=open(os.devnull, 'w'),
|
||||||
|
executable='/bin/bash',
|
||||||
|
universal_newlines=True).communicate()
|
||||||
|
|
||||||
|
# distro_id and distro_version_id will always be at least an empty string
|
||||||
|
distro_id, distro_version_id, distro_name = output[0].split('\n')
|
||||||
|
|
||||||
|
# if distro_version_id is empty string the major version will be empty
|
||||||
|
# string too
|
||||||
|
distro_major_version_id = distro_version_id.split('.')[0]
|
||||||
|
|
||||||
|
# check if that is UBI subcase?
|
||||||
|
if os.path.exists('/etc/yum.repos.d/ubi.repo'):
|
||||||
|
distro_id = 'ubi'
|
||||||
|
|
||||||
|
return distro_id, distro_major_version_id, distro_name
|
|
@ -15,9 +15,9 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
|
||||||
|
|
||||||
import configparser
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from .constants import (
|
from .constants import (
|
||||||
|
@ -33,6 +33,54 @@ from .exceptions import (
|
||||||
TripleOYumConfigNotFound,
|
TripleOYumConfigNotFound,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
py_version = sys.version_info.major
|
||||||
|
if py_version < 3:
|
||||||
|
import ConfigParser as cfg_parser
|
||||||
|
|
||||||
|
def save_section_to_file(file_path, config, section, updates):
|
||||||
|
"""Updates a specific 'section' in a 'config' and write to disk.
|
||||||
|
|
||||||
|
:param file_path: Absolute path to the file to be updated.
|
||||||
|
:param config: configparser object created from the file.
|
||||||
|
:param section: section name to be updated.
|
||||||
|
:param updates: dict with options to update in section.
|
||||||
|
"""
|
||||||
|
|
||||||
|
for k, v in updates.items():
|
||||||
|
config.set(section, k, v)
|
||||||
|
with open(file_path, 'w') as f:
|
||||||
|
config.write(f)
|
||||||
|
|
||||||
|
# NOTE(dviroel) Need to manually remove whitespaces around "=", to
|
||||||
|
# avoid legacy scripts failing on parsing ini files.
|
||||||
|
with open(file_path, 'r+') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
# erase content before writing again
|
||||||
|
f.truncate(0)
|
||||||
|
f.seek(0)
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
if "=" in line:
|
||||||
|
option_kv = line.split("=", 1)
|
||||||
|
option_kv = list(map(str.strip, option_kv))
|
||||||
|
f.write("%s%s%s\n" % (option_kv[0], "=", option_kv[1]))
|
||||||
|
else:
|
||||||
|
f.write(line + "\n")
|
||||||
|
|
||||||
|
else:
|
||||||
|
import configparser as cfg_parser
|
||||||
|
|
||||||
|
def save_section_to_file(file_path, config, section, updates):
|
||||||
|
"""Updates a specific 'section' in a 'config' and write to disk.
|
||||||
|
|
||||||
|
:param file_path: Absolute path to the file to be updated.
|
||||||
|
:param config: configparser object created from the file.
|
||||||
|
:param section: section name to be updated.
|
||||||
|
:param updates: dict with options to update in section.
|
||||||
|
"""
|
||||||
|
config[section].update(updates)
|
||||||
|
with open(file_path, 'w') as f:
|
||||||
|
config.write(f, space_around_delimiters=False)
|
||||||
|
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
@ -43,6 +91,21 @@ def validated_file_path(file_path):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def source_env_file(source_file, update=True):
|
||||||
|
"""Source a file and get all environment variables in a dict format."""
|
||||||
|
p_open = subprocess.Popen(". %s; env" % source_file,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
shell=True)
|
||||||
|
data = p_open.communicate()[0].decode('ascii')
|
||||||
|
|
||||||
|
env_dict = dict(
|
||||||
|
line.split("=", 1) for line in data.splitlines()
|
||||||
|
if len(line.split("=", 1)) > 1)
|
||||||
|
if update:
|
||||||
|
os.environ.update(env_dict)
|
||||||
|
return env_dict
|
||||||
|
|
||||||
|
|
||||||
class TripleOYumConfig:
|
class TripleOYumConfig:
|
||||||
"""
|
"""
|
||||||
This class is a base class for updating yum configuration files in
|
This class is a base class for updating yum configuration files in
|
||||||
|
@ -79,7 +142,8 @@ class TripleOYumConfig:
|
||||||
logger.addHandler(handler)
|
logger.addHandler(handler)
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
def __init__(self, valid_options=None, dir_path=None, file_extension=None):
|
def __init__(self, valid_options=None, dir_path=None, file_extension=None,
|
||||||
|
environment_file=None):
|
||||||
"""
|
"""
|
||||||
Creates a TripleOYumConfig object that holds configuration file
|
Creates a TripleOYumConfig object that holds configuration file
|
||||||
information.
|
information.
|
||||||
|
@ -90,10 +154,13 @@ class TripleOYumConfig:
|
||||||
for configuration files to be updated.
|
for configuration files to be updated.
|
||||||
:param: file_extension: File extension to filter configuration files
|
:param: file_extension: File extension to filter configuration files
|
||||||
in the search directory.
|
in the search directory.
|
||||||
|
:param environment_file: File to be read before updating environment
|
||||||
|
variables.
|
||||||
"""
|
"""
|
||||||
self.dir_path = dir_path
|
self.dir_path = dir_path
|
||||||
self.file_extension = file_extension
|
self.file_extension = file_extension
|
||||||
self.valid_options = valid_options
|
self.valid_options = valid_options
|
||||||
|
self.env_file = environment_file
|
||||||
|
|
||||||
# Sanity checks
|
# Sanity checks
|
||||||
if dir_path:
|
if dir_path:
|
||||||
|
@ -102,6 +169,9 @@ class TripleOYumConfig:
|
||||||
'provided path.').format(dir_path)
|
'provided path.').format(dir_path)
|
||||||
raise TripleOYumConfigNotFound(error_msg=msg)
|
raise TripleOYumConfigNotFound(error_msg=msg)
|
||||||
|
|
||||||
|
if self.env_file:
|
||||||
|
source_env_file(os.path.expanduser(self.env_file), update=True)
|
||||||
|
|
||||||
def _read_config_file(self, file_path, section=None):
|
def _read_config_file(self, file_path, section=None):
|
||||||
"""Reads a configuration file.
|
"""Reads a configuration file.
|
||||||
|
|
||||||
|
@ -109,7 +179,7 @@ class TripleOYumConfig:
|
||||||
to fail earlier if the section is not found.
|
to fail earlier if the section is not found.
|
||||||
:return: a config parser object and the full file path.
|
:return: a config parser object and the full file path.
|
||||||
"""
|
"""
|
||||||
config = configparser.ConfigParser()
|
config = cfg_parser.ConfigParser()
|
||||||
file_paths = [file_path]
|
file_paths = [file_path]
|
||||||
if self.dir_path:
|
if self.dir_path:
|
||||||
# if dir_path is configured, we can search for filename there
|
# if dir_path is configured, we can search for filename there
|
||||||
|
@ -127,7 +197,7 @@ class TripleOYumConfig:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config.read(valid_file_path)
|
config.read(valid_file_path)
|
||||||
except configparser.Error:
|
except cfg_parser.Error:
|
||||||
msg = 'Unable to parse configuration file {0}.'.format(
|
msg = 'Unable to parse configuration file {0}.'.format(
|
||||||
valid_file_path)
|
valid_file_path)
|
||||||
raise TripleOYumConfigFileParseError(error_msg=msg)
|
raise TripleOYumConfigFileParseError(error_msg=msg)
|
||||||
|
@ -161,10 +231,10 @@ class TripleOYumConfig:
|
||||||
if not os.access(os.path.join(self.dir_path, file), os.W_OK):
|
if not os.access(os.path.join(self.dir_path, file), os.W_OK):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
tmp_config = configparser.ConfigParser()
|
tmp_config = cfg_parser.ConfigParser()
|
||||||
try:
|
try:
|
||||||
tmp_config.read(os.path.join(self.dir_path, file))
|
tmp_config.read(os.path.join(self.dir_path, file))
|
||||||
except configparser.Error:
|
except cfg_parser.Error:
|
||||||
continue
|
continue
|
||||||
if section in tmp_config.sections():
|
if section in tmp_config.sections():
|
||||||
config_files_path.append(os.path.join(self.dir_path, file))
|
config_files_path.append(os.path.join(self.dir_path, file))
|
||||||
|
@ -195,12 +265,12 @@ class TripleOYumConfig:
|
||||||
'section {0}'.format(section))
|
'section {0}'.format(section))
|
||||||
raise TripleOYumConfigNotFound(error_msg=msg)
|
raise TripleOYumConfigNotFound(error_msg=msg)
|
||||||
|
|
||||||
|
for k, v in set_dict.items():
|
||||||
|
set_dict[k] = os.path.expandvars(v)
|
||||||
for file in files:
|
for file in files:
|
||||||
config, file = self._read_config_file(file, section=section)
|
config, file = self._read_config_file(file, section=section)
|
||||||
# Update configuration file with dict updates
|
# Update configuration file with dict updates
|
||||||
config[section].update(set_dict)
|
save_section_to_file(file, config, section, set_dict)
|
||||||
with open(file, 'w') as f:
|
|
||||||
config.write(f)
|
|
||||||
|
|
||||||
logging.info("Section '%s' was successfully "
|
logging.info("Section '%s' was successfully "
|
||||||
"updated.", section)
|
"updated.", section)
|
||||||
|
@ -213,6 +283,11 @@ class TripleOYumConfig:
|
||||||
new section.
|
new section.
|
||||||
:param file_path: Path to the configuration file to be updated.
|
:param file_path: Path to the configuration file to be updated.
|
||||||
"""
|
"""
|
||||||
|
if self.valid_options:
|
||||||
|
if not all(key in self.valid_options for key in add_dict.keys()):
|
||||||
|
msg = 'One or more provided options are not valid.'
|
||||||
|
raise TripleOYumConfigInvalidOption(error_msg=msg)
|
||||||
|
|
||||||
# This section shouldn't exist in the provided file
|
# This section shouldn't exist in the provided file
|
||||||
config, file_path = self._read_config_file(file_path=file_path)
|
config, file_path = self._read_config_file(file_path=file_path)
|
||||||
if section in config.sections():
|
if section in config.sections():
|
||||||
|
@ -220,13 +295,12 @@ class TripleOYumConfig:
|
||||||
"file.", section)
|
"file.", section)
|
||||||
raise TripleOYumConfigInvalidSection(error_msg=msg)
|
raise TripleOYumConfigInvalidSection(error_msg=msg)
|
||||||
|
|
||||||
|
for k, v in add_dict.items():
|
||||||
|
add_dict[k] = os.path.expandvars(v)
|
||||||
# Add new section
|
# Add new section
|
||||||
config.add_section(section)
|
config.add_section(section)
|
||||||
# Update configuration file with dict updates
|
# Update configuration file with dict updates
|
||||||
config[section].update(add_dict)
|
save_section_to_file(file_path, config, section, add_dict)
|
||||||
|
|
||||||
with open(file_path, '+w') as file:
|
|
||||||
config.write(file)
|
|
||||||
|
|
||||||
logging.info("Section '%s' was successfully "
|
logging.info("Section '%s' was successfully "
|
||||||
"added.", section)
|
"added.", section)
|
||||||
|
@ -245,10 +319,7 @@ class TripleOYumConfig:
|
||||||
|
|
||||||
config, file_path = self._read_config_file(file_path)
|
config, file_path = self._read_config_file(file_path)
|
||||||
for section in config.sections():
|
for section in config.sections():
|
||||||
config[section].update(set_dict)
|
save_section_to_file(file_path, config, section, set_dict)
|
||||||
|
|
||||||
with open(file_path, '+w') as file:
|
|
||||||
config.write(file)
|
|
||||||
|
|
||||||
logging.info("All sections for '%s' were successfully "
|
logging.info("All sections for '%s' were successfully "
|
||||||
"updated.", file_path)
|
"updated.", file_path)
|
||||||
|
@ -257,13 +328,14 @@ class TripleOYumConfig:
|
||||||
class TripleOYumRepoConfig(TripleOYumConfig):
|
class TripleOYumRepoConfig(TripleOYumConfig):
|
||||||
"""Manages yum repo configuration files."""
|
"""Manages yum repo configuration files."""
|
||||||
|
|
||||||
def __init__(self, dir_path=None):
|
def __init__(self, dir_path=None, environment_file=None):
|
||||||
conf_dir_path = dir_path or YUM_REPO_DIR
|
conf_dir_path = dir_path or YUM_REPO_DIR
|
||||||
|
|
||||||
super(TripleOYumRepoConfig, self).__init__(
|
super(TripleOYumRepoConfig, self).__init__(
|
||||||
valid_options=YUM_REPO_SUPPORTED_OPTIONS,
|
valid_options=YUM_REPO_SUPPORTED_OPTIONS,
|
||||||
dir_path=conf_dir_path,
|
dir_path=conf_dir_path,
|
||||||
file_extension=YUM_REPO_FILE_EXTENSION)
|
file_extension=YUM_REPO_FILE_EXTENSION,
|
||||||
|
environment_file=environment_file)
|
||||||
|
|
||||||
def update_section(
|
def update_section(
|
||||||
self, section, set_dict=None, file_path=None, enabled=None):
|
self, section, set_dict=None, file_path=None, enabled=None):
|
||||||
|
@ -274,11 +346,36 @@ class TripleOYumRepoConfig(TripleOYumConfig):
|
||||||
super(TripleOYumRepoConfig, self).update_section(
|
super(TripleOYumRepoConfig, self).update_section(
|
||||||
section, update_dict, file_path=file_path)
|
section, update_dict, file_path=file_path)
|
||||||
|
|
||||||
|
def add_section(self, section, add_dict, file_path, enabled=None):
|
||||||
|
update_dict = add_dict or {}
|
||||||
|
if enabled is not None:
|
||||||
|
update_dict['enabled'] = '1' if enabled else '0'
|
||||||
|
super(TripleOYumRepoConfig, self).add_section(
|
||||||
|
section, update_dict, file_path)
|
||||||
|
|
||||||
|
def add_or_update_section(self, section, set_dict=None, file_path=None,
|
||||||
|
enabled=None, create_if_not_exists=True):
|
||||||
|
try:
|
||||||
|
self.update_section(
|
||||||
|
section, set_dict=set_dict, file_path=file_path,
|
||||||
|
enabled=enabled)
|
||||||
|
except TripleOYumConfigNotFound:
|
||||||
|
if not create_if_not_exists or file_path is None:
|
||||||
|
# there is nothing to do, we can't create a new config file
|
||||||
|
raise
|
||||||
|
# Create a new file if it does not exists
|
||||||
|
with open(file_path, 'w+'):
|
||||||
|
pass
|
||||||
|
# When creating a new repo file, make sure that it has a name
|
||||||
|
if 'name' not in set_dict.keys():
|
||||||
|
set_dict['name'] = section
|
||||||
|
self.add_section(section, set_dict, file_path, enabled=enabled)
|
||||||
|
|
||||||
|
|
||||||
class TripleOYumGlobalConfig(TripleOYumConfig):
|
class TripleOYumGlobalConfig(TripleOYumConfig):
|
||||||
"""Manages yum global configuration file."""
|
"""Manages yum global configuration file."""
|
||||||
|
|
||||||
def __init__(self, file_path=None):
|
def __init__(self, file_path=None, environment_file=None):
|
||||||
self.conf_file_path = file_path or YUM_GLOBAL_CONFIG_FILE_PATH
|
self.conf_file_path = file_path or YUM_GLOBAL_CONFIG_FILE_PATH
|
||||||
logging.info("Using '%s' as yum global configuration "
|
logging.info("Using '%s' as yum global configuration "
|
||||||
"file.", self.conf_file_path)
|
"file.", self.conf_file_path)
|
||||||
|
@ -290,13 +387,14 @@ class TripleOYumGlobalConfig(TripleOYumConfig):
|
||||||
# create it. If the user specify another conf file that doesn't
|
# create it. If the user specify another conf file that doesn't
|
||||||
# exists, the operation will fail.
|
# exists, the operation will fail.
|
||||||
if not os.path.isfile(self.conf_file_path):
|
if not os.path.isfile(self.conf_file_path):
|
||||||
config = configparser.ConfigParser()
|
config = cfg_parser.ConfigParser()
|
||||||
config.read(self.conf_file_path)
|
config.read(self.conf_file_path)
|
||||||
config.add_section('main')
|
config.add_section('main')
|
||||||
with open(self.conf_file_path, '+w') as file:
|
with open(self.conf_file_path, 'w+') as file:
|
||||||
config.write(file)
|
config.write(file)
|
||||||
|
|
||||||
super(TripleOYumGlobalConfig, self).__init__()
|
super(TripleOYumGlobalConfig, self).__init__(
|
||||||
|
environment_file=environment_file)
|
||||||
|
|
||||||
def update_section(self, section, set_dict, file_path=None):
|
def update_section(self, section, set_dict, file_path=None):
|
||||||
super(TripleOYumGlobalConfig, self).update_section(
|
super(TripleOYumGlobalConfig, self).update_section(
|
||||||
|
|
|
@ -66,6 +66,11 @@ options:
|
||||||
file to be changed.
|
file to be changed.
|
||||||
type: path
|
type: path
|
||||||
default: /etc/yum.repos.d
|
default: /etc/yum.repos.d
|
||||||
|
environment_file:
|
||||||
|
description:
|
||||||
|
- Absolute path to an environment file to be read before updating or
|
||||||
|
creating yum config and repo files.
|
||||||
|
type: path
|
||||||
compose_url:
|
compose_url:
|
||||||
description:
|
description:
|
||||||
- URL that contains CentOS compose repositories.
|
- URL that contains CentOS compose repositories.
|
||||||
|
@ -151,7 +156,7 @@ EXAMPLES = r'''
|
||||||
- name: Configure a set of repos based on latest CentOS Stream 8 compose
|
- name: Configure a set of repos based on latest CentOS Stream 8 compose
|
||||||
become: true
|
become: true
|
||||||
become_user: root
|
become_user: root
|
||||||
tripleo_yup_config:
|
tripleo_yum_config:
|
||||||
compose_url: https://composes.centos.org/latest-CentOS-Stream-8/compose/
|
compose_url: https://composes.centos.org/latest-CentOS-Stream-8/compose/
|
||||||
centos_release: centos-stream-8
|
centos_release: centos-stream-8
|
||||||
variants:
|
variants:
|
||||||
|
@ -165,6 +170,7 @@ EXAMPLES = r'''
|
||||||
|
|
||||||
RETURN = r''' # '''
|
RETURN = r''' # '''
|
||||||
|
|
||||||
|
from ansible.module_utils import six # noqa: E402
|
||||||
from ansible.module_utils.basic import AnsibleModule # noqa: E402
|
from ansible.module_utils.basic import AnsibleModule # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
|
@ -172,10 +178,13 @@ def run_module():
|
||||||
try:
|
try:
|
||||||
import ansible_collections.tripleo.repos.plugins.module_utils. \
|
import ansible_collections.tripleo.repos.plugins.module_utils. \
|
||||||
tripleo_repos.yum_config.constants as const
|
tripleo_repos.yum_config.constants as const
|
||||||
|
import ansible_collections.tripleo.repos.plugins.module_utils. \
|
||||||
|
tripleo_repos.yum_config.utils as utils
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import tripleo_repos.yum_config.constants as const
|
import tripleo_repos.yum_config.constants as const
|
||||||
# define available arguments/parameters a user can pass to the module
|
import tripleo_repos.yum_config.utils as utils
|
||||||
supported_config_types = ['repo', 'module', 'global',
|
|
||||||
|
supported_config_types = ['repo', 'global', 'module',
|
||||||
'enable-compose-repos']
|
'enable-compose-repos']
|
||||||
supported_module_operations = ['install', 'remove', 'reset']
|
supported_module_operations = ['install', 'remove', 'reset']
|
||||||
module_args = dict(
|
module_args = dict(
|
||||||
|
@ -188,6 +197,7 @@ def run_module():
|
||||||
set_options=dict(type='dict', default={}),
|
set_options=dict(type='dict', default={}),
|
||||||
file_path=dict(type='path'),
|
file_path=dict(type='path'),
|
||||||
dir_path=dict(type='path', default=const.YUM_REPO_DIR),
|
dir_path=dict(type='path', default=const.YUM_REPO_DIR),
|
||||||
|
environment_file=dict(type='path'),
|
||||||
compose_url=dict(type='str'),
|
compose_url=dict(type='str'),
|
||||||
centos_release=dict(type='str',
|
centos_release=dict(type='str',
|
||||||
choices=const.COMPOSE_REPOS_RELEASES),
|
choices=const.COMPOSE_REPOS_RELEASES),
|
||||||
|
@ -199,17 +209,37 @@ def run_module():
|
||||||
disable_repos=dict(type='list', default=[],
|
disable_repos=dict(type='list', default=[],
|
||||||
elements='str'),
|
elements='str'),
|
||||||
)
|
)
|
||||||
|
required_if_params = [
|
||||||
|
["type", "repo", ["name"]],
|
||||||
|
["type", "module", ["name"]],
|
||||||
|
["type", "enable-compose-repos", ["compose_url"]]
|
||||||
|
]
|
||||||
|
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec=module_args,
|
argument_spec=module_args,
|
||||||
required_if=[
|
required_if=required_if_params,
|
||||||
["type", "repo", ["name"]],
|
|
||||||
["type", "module", ["name"]],
|
|
||||||
["type", "enable-compose-repos", ["compose_url"]],
|
|
||||||
],
|
|
||||||
supports_check_mode=False
|
supports_check_mode=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
operations_not_supp_in_py2 = ['module', 'enable-compose-repos']
|
||||||
|
if six.PY2 and module.params['type'] in operations_not_supp_in_py2:
|
||||||
|
msg = ("The configuration type '{0}' is not "
|
||||||
|
"supported with python 2.").format(module.params['type'])
|
||||||
|
module.fail_json(msg=msg)
|
||||||
|
|
||||||
|
distro, major_version, __ = utils.get_distro_info()
|
||||||
|
dnf_module_support = False
|
||||||
|
for min_distro_ver in const.DNF_MODULE_MINIMAL_DISTRO_VERSIONS:
|
||||||
|
if (distro == min_distro_ver.get('distro') and int(
|
||||||
|
major_version) >= min_distro_ver.get('min_version')):
|
||||||
|
dnf_module_support = True
|
||||||
|
break
|
||||||
|
if module.params['type'] == 'module' and not dnf_module_support:
|
||||||
|
msg = ("The configuration type 'module' is not "
|
||||||
|
"supported in this distro version "
|
||||||
|
"({0}-{1}).".format(distro, major_version))
|
||||||
|
module.fail_json(msg=msg)
|
||||||
|
|
||||||
# 'set_options' expects a dict that can also contains a list of values.
|
# 'set_options' expects a dict that can also contains a list of values.
|
||||||
# List of elements will be converted to a comma-separated list
|
# List of elements will be converted to a comma-separated list
|
||||||
m_set_opts = module.params.get('set_options')
|
m_set_opts = module.params.get('set_options')
|
||||||
|
@ -223,33 +253,41 @@ def run_module():
|
||||||
# Module execution
|
# Module execution
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
import ansible_collections.tripleo.repos.plugins.module_utils.\
|
|
||||||
tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
|
||||||
import ansible_collections.tripleo.repos.plugins.module_utils.\
|
import ansible_collections.tripleo.repos.plugins.module_utils.\
|
||||||
tripleo_repos.yum_config.yum_config as cfg
|
tripleo_repos.yum_config.yum_config as cfg
|
||||||
import ansible_collections.tripleo.repos.plugins.module_utils. \
|
|
||||||
tripleo_repos.yum_config.compose_repos as repos
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
|
||||||
import tripleo_repos.yum_config.yum_config as cfg
|
import tripleo_repos.yum_config.yum_config as cfg
|
||||||
import tripleo_repos.yum_config.compose_repos as repos
|
|
||||||
|
|
||||||
if module.params['type'] == 'repo':
|
if module.params['type'] == 'repo':
|
||||||
config_obj = cfg.TripleOYumRepoConfig(
|
config_obj = cfg.TripleOYumRepoConfig(
|
||||||
dir_path=module.params['dir_path'])
|
dir_path=module.params['dir_path'],
|
||||||
config_obj.update_section(
|
environment_file=module.params['environment_file'])
|
||||||
|
config_obj.add_or_update_section(
|
||||||
module.params['name'],
|
module.params['name'],
|
||||||
m_set_opts,
|
set_dict=m_set_opts,
|
||||||
file_path=module.params['file_path'],
|
file_path=module.params['file_path'],
|
||||||
enabled=module.params['enabled'])
|
enabled=module.params['enabled'])
|
||||||
|
|
||||||
|
elif module.params['type'] == 'global':
|
||||||
|
config_obj = cfg.TripleOYumGlobalConfig(
|
||||||
|
file_path=module.params['file_path'],
|
||||||
|
environment_file=module.params['environment_file'])
|
||||||
|
config_obj.update_section('main', m_set_opts)
|
||||||
|
|
||||||
elif module.params['type'] == 'enable-compose-repos':
|
elif module.params['type'] == 'enable-compose-repos':
|
||||||
|
try:
|
||||||
|
import ansible_collections.tripleo.repos.plugins.module_utils.\
|
||||||
|
tripleo_repos.yum_config.compose_repos as repos
|
||||||
|
except ImportError:
|
||||||
|
import tripleo_repos.yum_config.compose_repos as repos
|
||||||
|
|
||||||
# 1. Create compose repo config object
|
# 1. Create compose repo config object
|
||||||
repo_obj = repos.TripleOYumComposeRepoConfig(
|
repo_obj = repos.TripleOYumComposeRepoConfig(
|
||||||
module.params['compose_url'],
|
module.params['compose_url'],
|
||||||
module.params['centos_release'],
|
module.params['centos_release'],
|
||||||
dir_path=module.params['dir_path'],
|
dir_path=module.params['dir_path'],
|
||||||
arch=module.params['arch'])
|
arch=module.params['arch'],
|
||||||
|
environment_file=module.params['environment_file'])
|
||||||
# 2. enable CentOS compose repos
|
# 2. enable CentOS compose repos
|
||||||
repo_obj.enable_compose_repos(
|
repo_obj.enable_compose_repos(
|
||||||
variants=module.params['variants'],
|
variants=module.params['variants'],
|
||||||
|
@ -259,6 +297,12 @@ def run_module():
|
||||||
repo_obj.update_all_sections(file, enabled=False)
|
repo_obj.update_all_sections(file, enabled=False)
|
||||||
|
|
||||||
elif module.params['type'] == 'module':
|
elif module.params['type'] == 'module':
|
||||||
|
try:
|
||||||
|
import ansible_collections.tripleo.repos.plugins.module_utils.\
|
||||||
|
tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
||||||
|
except ImportError:
|
||||||
|
import tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
||||||
|
|
||||||
dnf_mod_mgr = dnf_mgr.DnfModuleManager()
|
dnf_mod_mgr = dnf_mgr.DnfModuleManager()
|
||||||
if module.params['enabled']:
|
if module.params['enabled']:
|
||||||
dnf_mod_mgr.enable_module(module.params['name'],
|
dnf_mod_mgr.enable_module(module.params['name'],
|
||||||
|
@ -275,11 +319,6 @@ def run_module():
|
||||||
stream=module.params['stream'],
|
stream=module.params['stream'],
|
||||||
profile=module.params['profile'])
|
profile=module.params['profile'])
|
||||||
|
|
||||||
elif module.params['type'] == 'global':
|
|
||||||
config_obj = cfg.TripleOYumGlobalConfig(
|
|
||||||
file_path=module.params['file_path'])
|
|
||||||
config_obj.update_section('main', m_set_opts)
|
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
module.fail_json(msg=str(exc))
|
module.fail_json(msg=str(exc))
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ FAKE_SET_DICT = {
|
||||||
FAKE_COMPOSE_URL = (
|
FAKE_COMPOSE_URL = (
|
||||||
'https://composes.centos.org/fake-CentOS-Stream/compose/')
|
'https://composes.centos.org/fake-CentOS-Stream/compose/')
|
||||||
FAKE_REPO_PATH = '/etc/yum.repos.d/fake.repo'
|
FAKE_REPO_PATH = '/etc/yum.repos.d/fake.repo'
|
||||||
|
FAKE_RELEASE_NAME = 'fake_release'
|
||||||
|
|
||||||
FAKE_COMPOSE_INFO = {
|
FAKE_COMPOSE_INFO = {
|
||||||
"header": {
|
"header": {
|
||||||
|
@ -79,13 +80,26 @@ FAKE_COMPOSE_INFO = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FAKE_ENV_OUTPUT = """
|
||||||
|
LANG=C.utf8
|
||||||
|
HOSTNAME=4cb7d7db1907
|
||||||
|
which_declare=declare -f
|
||||||
|
container=oci
|
||||||
|
PWD=/
|
||||||
|
HOME=/root
|
||||||
|
TERM=xterm
|
||||||
|
SHLVL=1
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
|
_=/usr/bin/env
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class FakeConfigParser(dict):
|
class FakeConfigParser(dict):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(FakeConfigParser, self).__init__(*args, **kwargs)
|
super(FakeConfigParser, self).__init__(*args, **kwargs)
|
||||||
self.__dict__ = self
|
self.__dict__ = self
|
||||||
|
|
||||||
def write(self, file):
|
def write(self, file, space_around_delimiters=False):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def read(self, file):
|
def read(self, file):
|
||||||
|
|
|
@ -23,6 +23,7 @@ import tripleo_repos.yum_config.__main__ as main
|
||||||
import tripleo_repos.yum_config.compose_repos as repos
|
import tripleo_repos.yum_config.compose_repos as repos
|
||||||
import tripleo_repos.yum_config.constants as const
|
import tripleo_repos.yum_config.constants as const
|
||||||
import tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
import tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
||||||
|
import tripleo_repos.yum_config.utils as utils
|
||||||
import tripleo_repos.yum_config.yum_config as yum_cfg
|
import tripleo_repos.yum_config.yum_config as yum_cfg
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,13 +45,19 @@ class TestTripleoYumConfigBase(unittest.TestCase):
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class TestTripleoYumConfigMain(TestTripleoYumConfigBase):
|
class TestTripleoYumConfigMain(TestTripleoYumConfigBase):
|
||||||
"""Test class for main method operations."""
|
"""Test class for main method operations."""
|
||||||
|
def setUp(self):
|
||||||
|
super(TestTripleoYumConfigMain, self).setUp()
|
||||||
|
self.mock_object(utils, 'get_distro_info',
|
||||||
|
mock.Mock(return_value=("centos", "8", None)))
|
||||||
|
|
||||||
def test_main_repo(self):
|
def test_main_repo(self):
|
||||||
sys.argv[1:] = ['repo', 'fake_repo', '--enable',
|
sys.argv[1:] = ['repo', 'fake_repo', '--enable',
|
||||||
'--set-opts', 'key1=value1', 'key2=value2',
|
'--set-opts', 'key1=value1', 'key2=value2',
|
||||||
'--config-file-path', fakes.FAKE_FILE_PATH]
|
'--config-file-path', fakes.FAKE_FILE_PATH]
|
||||||
|
|
||||||
yum_repo_obj = mock.Mock()
|
yum_repo_obj = mock.Mock()
|
||||||
mock_update_section = self.mock_object(yum_repo_obj, 'update_section')
|
mock_update_section = self.mock_object(yum_repo_obj,
|
||||||
|
'add_or_update_section')
|
||||||
mock_yum_repo_obj = self.mock_object(
|
mock_yum_repo_obj = self.mock_object(
|
||||||
yum_cfg, 'TripleOYumRepoConfig',
|
yum_cfg, 'TripleOYumRepoConfig',
|
||||||
mock.Mock(return_value=yum_repo_obj))
|
mock.Mock(return_value=yum_repo_obj))
|
||||||
|
@ -58,10 +65,11 @@ class TestTripleoYumConfigMain(TestTripleoYumConfigBase):
|
||||||
main.main()
|
main.main()
|
||||||
expected_dict = {'key1': 'value1', 'key2': 'value2'}
|
expected_dict = {'key1': 'value1', 'key2': 'value2'}
|
||||||
|
|
||||||
mock_yum_repo_obj.assert_called_once_with(dir_path=const.YUM_REPO_DIR)
|
mock_yum_repo_obj.assert_called_once_with(dir_path=const.YUM_REPO_DIR,
|
||||||
|
environment_file=None)
|
||||||
mock_update_section.assert_called_once_with(
|
mock_update_section.assert_called_once_with(
|
||||||
'fake_repo', expected_dict, file_path=fakes.FAKE_FILE_PATH,
|
'fake_repo', set_dict=expected_dict,
|
||||||
enabled=True)
|
file_path=fakes.FAKE_FILE_PATH, enabled=True)
|
||||||
|
|
||||||
@ddt.data('enable', 'disable', 'reset', 'install', 'remove')
|
@ddt.data('enable', 'disable', 'reset', 'install', 'remove')
|
||||||
def test_main_module(self, operation):
|
def test_main_module(self, operation):
|
||||||
|
@ -92,7 +100,8 @@ class TestTripleoYumConfigMain(TestTripleoYumConfigBase):
|
||||||
main.main()
|
main.main()
|
||||||
expected_dict = {'key1': 'value1', 'key2': 'value2'}
|
expected_dict = {'key1': 'value1', 'key2': 'value2'}
|
||||||
|
|
||||||
mock_yum_global_obj.assert_called_once_with(file_path=None)
|
mock_yum_global_obj.assert_called_once_with(file_path=None,
|
||||||
|
environment_file=None)
|
||||||
mock_update_section.assert_called_once_with('main', expected_dict)
|
mock_update_section.assert_called_once_with('main', expected_dict)
|
||||||
|
|
||||||
def test_main_no_command(self):
|
def test_main_no_command(self):
|
||||||
|
@ -143,9 +152,20 @@ class TestTripleoYumConfigMain(TestTripleoYumConfigBase):
|
||||||
fakes.FAKE_COMPOSE_URL,
|
fakes.FAKE_COMPOSE_URL,
|
||||||
const.COMPOSE_REPOS_RELEASES[0],
|
const.COMPOSE_REPOS_RELEASES[0],
|
||||||
dir_path=const.YUM_REPO_DIR,
|
dir_path=const.YUM_REPO_DIR,
|
||||||
arch=const.COMPOSE_REPOS_SUPPORTED_ARCHS[0])
|
arch=const.COMPOSE_REPOS_SUPPORTED_ARCHS[0],
|
||||||
|
environment_file=None)
|
||||||
mock_enable_composes.assert_called_once_with(
|
mock_enable_composes.assert_called_once_with(
|
||||||
variants=['fake_variant'], override_repos=False)
|
variants=['fake_variant'], override_repos=False)
|
||||||
mock_update_all.assert_called_once_with(
|
mock_update_all.assert_called_once_with(
|
||||||
fakes.FAKE_REPO_PATH, enabled=False
|
fakes.FAKE_REPO_PATH, enabled=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_main_invalid_release_for_dnf_module(self):
|
||||||
|
self.mock_object(utils, 'get_distro_info',
|
||||||
|
mock.Mock(return_value=("centos", "7", None)))
|
||||||
|
sys.argv[1:] = ['module', 'enable', 'fake_module']
|
||||||
|
|
||||||
|
with self.assertRaises(SystemExit) as command:
|
||||||
|
main.main()
|
||||||
|
|
||||||
|
self.assertEqual(2, command.exception.code)
|
||||||
|
|
|
@ -16,6 +16,7 @@ import configparser
|
||||||
import copy
|
import copy
|
||||||
import ddt
|
import ddt
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from . import fakes
|
from . import fakes
|
||||||
|
@ -226,17 +227,44 @@ class TestTripleOYumConfig(test_main.TestTripleoYumConfigBase):
|
||||||
|
|
||||||
mock_read_config.assert_called_once_with(fakes.FAKE_FILE_PATH)
|
mock_read_config.assert_called_once_with(fakes.FAKE_FILE_PATH)
|
||||||
|
|
||||||
|
def test_source_env_file(self):
|
||||||
|
p_open_mock = mock.Mock()
|
||||||
|
mock_open = self.mock_object(subprocess, 'Popen',
|
||||||
|
mock.Mock(return_value=p_open_mock))
|
||||||
|
data_mock = mock.Mock()
|
||||||
|
self.mock_object(data_mock, 'decode',
|
||||||
|
mock.Mock(return_value=fakes.FAKE_ENV_OUTPUT))
|
||||||
|
self.mock_object(p_open_mock, 'communicate',
|
||||||
|
mock.Mock(return_value=[data_mock]))
|
||||||
|
env_update_mock = self.mock_object(os.environ, 'update')
|
||||||
|
|
||||||
|
yum_cfg.source_env_file('fake_source_file', update=True)
|
||||||
|
|
||||||
|
exp_env_dict = dict(
|
||||||
|
line.split("=", 1) for line in fakes.FAKE_ENV_OUTPUT.splitlines()
|
||||||
|
if len(line.split("=", 1)) > 1)
|
||||||
|
|
||||||
|
mock_open.assert_called_once_with(". fake_source_file; env",
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
shell=True)
|
||||||
|
env_update_mock.assert_called_once_with(exp_env_dict)
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class TestTripleOYumRepoConfig(test_main.TestTripleoYumConfigBase):
|
class TestTripleOYumRepoConfig(test_main.TestTripleoYumConfigBase):
|
||||||
"""Tests for TripleOYumRepoConfig class and its methods."""
|
"""Tests for TripleOYumRepoConfig class and its methods."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestTripleOYumRepoConfig, self).setUp()
|
||||||
|
self.config_obj = yum_cfg.TripleOYumRepoConfig(
|
||||||
|
dir_path='/tmp'
|
||||||
|
)
|
||||||
|
|
||||||
@ddt.data(True, False, None)
|
@ddt.data(True, False, None)
|
||||||
def test_yum_repo_config_update_section(self, enable):
|
def test_yum_repo_config_update_section(self, enable):
|
||||||
self.mock_object(os.path, 'isfile')
|
self.mock_object(os.path, 'isfile')
|
||||||
self.mock_object(os, 'access')
|
self.mock_object(os, 'access')
|
||||||
self.mock_object(os.path, 'isdir')
|
self.mock_object(os.path, 'isdir')
|
||||||
cfg_obj = yum_cfg.TripleOYumRepoConfig()
|
|
||||||
|
|
||||||
mock_update = self.mock_object(yum_cfg.TripleOYumConfig,
|
mock_update = self.mock_object(yum_cfg.TripleOYumConfig,
|
||||||
'update_section')
|
'update_section')
|
||||||
|
@ -246,13 +274,78 @@ class TestTripleOYumRepoConfig(test_main.TestTripleoYumConfigBase):
|
||||||
if enable is not None:
|
if enable is not None:
|
||||||
expected_updates['enabled'] = '1' if enable else '0'
|
expected_updates['enabled'] = '1' if enable else '0'
|
||||||
|
|
||||||
cfg_obj.update_section(fakes.FAKE_SECTION1, set_dict=updates,
|
self.config_obj.update_section(
|
||||||
file_path=fakes.FAKE_FILE_PATH, enabled=enable)
|
fakes.FAKE_SECTION1, set_dict=updates,
|
||||||
|
file_path=fakes.FAKE_FILE_PATH, enabled=enable)
|
||||||
|
|
||||||
mock_update.assert_called_once_with(fakes.FAKE_SECTION1,
|
mock_update.assert_called_once_with(fakes.FAKE_SECTION1,
|
||||||
expected_updates,
|
expected_updates,
|
||||||
file_path=fakes.FAKE_FILE_PATH)
|
file_path=fakes.FAKE_FILE_PATH)
|
||||||
|
|
||||||
|
@mock.patch('builtins.open')
|
||||||
|
def test_add_or_update_section(self, open):
|
||||||
|
mock_update = self.mock_object(
|
||||||
|
self.config_obj, 'update_section',
|
||||||
|
mock.Mock(side_effect=exc.TripleOYumConfigNotFound(
|
||||||
|
error_msg='error')))
|
||||||
|
mock_add_section = self.mock_object(self.config_obj, 'add_section')
|
||||||
|
|
||||||
|
self.config_obj.add_or_update_section(
|
||||||
|
fakes.FAKE_SECTION1,
|
||||||
|
set_dict=fakes.FAKE_SET_DICT,
|
||||||
|
file_path=fakes.FAKE_FILE_PATH,
|
||||||
|
enabled=True,
|
||||||
|
create_if_not_exists=True)
|
||||||
|
|
||||||
|
mock_update.assert_called_once_with(fakes.FAKE_SECTION1,
|
||||||
|
set_dict=fakes.FAKE_SET_DICT,
|
||||||
|
file_path=fakes.FAKE_FILE_PATH,
|
||||||
|
enabled=True)
|
||||||
|
fake_set_dict = copy.deepcopy(fakes.FAKE_SET_DICT)
|
||||||
|
fake_set_dict['name'] = fakes.FAKE_SECTION1
|
||||||
|
mock_add_section.assert_called_once_with(
|
||||||
|
fakes.FAKE_SECTION1,
|
||||||
|
fake_set_dict,
|
||||||
|
fakes.FAKE_FILE_PATH,
|
||||||
|
enabled=True)
|
||||||
|
|
||||||
|
@ddt.data((fakes.FAKE_FILE_PATH, False), (None, True))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_add_or_update_section_file_not_found(self, fake_path,
|
||||||
|
create_if_not_exists):
|
||||||
|
mock_update = self.mock_object(
|
||||||
|
self.config_obj, 'update_section',
|
||||||
|
mock.Mock(side_effect=exc.TripleOYumConfigNotFound(
|
||||||
|
error_msg='error')))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exc.TripleOYumConfigNotFound,
|
||||||
|
self.config_obj.add_or_update_section,
|
||||||
|
fakes.FAKE_SECTION1,
|
||||||
|
set_dict=fakes.FAKE_SET_DICT,
|
||||||
|
file_path=fake_path,
|
||||||
|
enabled=True,
|
||||||
|
create_if_not_exists=create_if_not_exists)
|
||||||
|
|
||||||
|
mock_update.assert_called_once_with(fakes.FAKE_SECTION1,
|
||||||
|
set_dict=fakes.FAKE_SET_DICT,
|
||||||
|
file_path=fake_path,
|
||||||
|
enabled=True)
|
||||||
|
|
||||||
|
@ddt.data(None, False, True)
|
||||||
|
def test_add_section(self, enabled):
|
||||||
|
mock_add = self.mock_object(yum_cfg.TripleOYumConfig, 'add_section')
|
||||||
|
|
||||||
|
self.config_obj.add_section(
|
||||||
|
fakes.FAKE_SECTION1, fakes.FAKE_SET_DICT,
|
||||||
|
fakes.FAKE_FILE_PATH, enabled=enabled)
|
||||||
|
|
||||||
|
updated_dict = copy.deepcopy(fakes.FAKE_SET_DICT)
|
||||||
|
if enabled is not None:
|
||||||
|
updated_dict['enabled'] = '1' if enabled else '0'
|
||||||
|
mock_add.assert_called_once_with(fakes.FAKE_SECTION1, updated_dict,
|
||||||
|
fakes.FAKE_FILE_PATH)
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class TestTripleOYumGlobalConfig(test_main.TestTripleoYumConfigBase):
|
class TestTripleOYumGlobalConfig(test_main.TestTripleoYumConfigBase):
|
||||||
|
|
Loading…
Reference in New Issue