Improvements to yum-config module
This patch adds a couple of improvements to yum-config module: - change the default behavior for yum-config repo, which now tries to update an existent configuration file and, if the file does not exists, create a new one. - Adds more options to repo config operation. - Check OS version info before enable dnf-manager command. - Add python2 support to yum-config 'repo' and 'global'. - Update molecule to run yum-config 'repo' and 'global' tests for CentOS-7 Change-Id: I654fb32ad4e987b43baea17641aa60de86a78ff9 Signed-off-by: Douglas Viroel <dviroel@redhat.com>
This commit is contained in:
parent
a34103fffd
commit
9efbbc2bcb
|
@ -13,34 +13,47 @@
|
|||
register: result
|
||||
failed_when: result is success
|
||||
|
||||
- name: "Disable one of the system repos"
|
||||
- name: "Test disable system repo"
|
||||
become: true
|
||||
tripleo.repos.yum_config:
|
||||
type: repo
|
||||
name: rt
|
||||
file_path: /etc/yum.repos.d/CentOS-Stream-RealTime.repo
|
||||
name: "{{ 'rt' if (ansible_distribution_major_version is version(8, '>=')) else 'cr' }}"
|
||||
enabled: false
|
||||
tags:
|
||||
# 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
|
||||
# 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
|
||||
tripleo.repos.yum_config:
|
||||
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:
|
||||
skip_if_unavailable: "False"
|
||||
keepcache: "0"
|
||||
fake_conf: "True"
|
||||
tags:
|
||||
# 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
|
||||
# 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"
|
||||
become: true
|
||||
|
|
|
@ -2,32 +2,33 @@
|
|||
- name: Verify
|
||||
hosts: all
|
||||
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
|
||||
with_items:
|
||||
- name: RealTime
|
||||
path: /etc/yum.repos.d/CentOS-Stream-RealTime.repo
|
||||
section: rt
|
||||
- name: "{{ section_name|upper }}"
|
||||
path: "{{ repo_path }}"
|
||||
section: "{{ section_name }}"
|
||||
key: enabled
|
||||
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
|
||||
with_items:
|
||||
- name: dnf.conf
|
||||
path: /etc/dnf/dnf.conf
|
||||
- name: global_conf
|
||||
path: "{{ conf_file_path }}"
|
||||
section: main
|
||||
key: skip_if_unavailable
|
||||
value: "False"
|
||||
- name: dnf.conf
|
||||
path: /etc/dnf/dnf.conf
|
||||
- name: global_conf
|
||||
path: "{{ conf_file_path }}"
|
||||
section: main
|
||||
key: keepcache
|
||||
value: "0"
|
||||
# TODO: code needs a fix to be compatible with CentOS-7
|
||||
when: ansible_distribution_major_version is version(8, '>=')
|
||||
key: fake_conf
|
||||
value: "True"
|
||||
|
||||
- name: Validate compose repos outputs
|
||||
include_tasks: verify_compose_repos.yml
|
||||
|
|
|
@ -17,10 +17,9 @@ import argparse
|
|||
import logging
|
||||
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.dnf_manager as dnf_mgr
|
||||
import tripleo_repos.yum_config.yum_config as cfg
|
||||
import tripleo_repos.yum_config.utils as utils
|
||||
|
||||
|
||||
def options_to_dict(options):
|
||||
|
@ -39,6 +38,12 @@ def options_to_dict(options):
|
|||
|
||||
def main():
|
||||
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_args_parser = argparse.ArgumentParser(add_help=False)
|
||||
|
@ -47,6 +52,15 @@ def main():
|
|||
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.add_argument(
|
||||
'--enable',
|
||||
|
@ -171,24 +185,32 @@ def main():
|
|||
# Subcommands
|
||||
subparsers.add_parser(
|
||||
'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'
|
||||
)
|
||||
subparsers.add_parser(
|
||||
'global',
|
||||
parents=[common_parse, environment_parse, options_parse],
|
||||
help='updates global yum configuration options'
|
||||
)
|
||||
|
||||
if py_version >= 3:
|
||||
subparsers.add_parser(
|
||||
'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'
|
||||
)
|
||||
subparsers.add_parser(
|
||||
'global',
|
||||
parents=[common_parse, options_parse],
|
||||
help='updates global yum configuration options'
|
||||
)
|
||||
subparsers.add_parser(
|
||||
'enable-compose-repos',
|
||||
parents=[compose_args_parser],
|
||||
help='enable CentOS compose repos based on an compose url.'
|
||||
)
|
||||
break
|
||||
|
||||
args = main_parser.parse_args()
|
||||
if args.command is None:
|
||||
|
@ -202,13 +224,14 @@ def main():
|
|||
if args.command == 'repo':
|
||||
set_dict = options_to_dict(args.set_opts)
|
||||
config_obj = cfg.TripleOYumRepoConfig(
|
||||
dir_path=args.config_dir_path)
|
||||
|
||||
config_obj.update_section(args.name, set_dict,
|
||||
dir_path=args.config_dir_path,
|
||||
environment_file=args.env_file)
|
||||
config_obj.add_or_update_section(args.name, set_dict=set_dict,
|
||||
file_path=args.config_file_path,
|
||||
enabled=args.enable)
|
||||
|
||||
elif args.command == 'module':
|
||||
import tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
||||
dnf_mod_mgr = dnf_mgr.DnfModuleManager()
|
||||
dnf_method = getattr(dnf_mod_mgr, args.operation + "_module")
|
||||
dnf_method(args.name, stream=args.stream, profile=args.profile)
|
||||
|
@ -216,16 +239,19 @@ def main():
|
|||
elif args.command == 'global':
|
||||
set_dict = options_to_dict(args.set_opts)
|
||||
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)
|
||||
|
||||
elif args.command == 'enable-compose-repos':
|
||||
import tripleo_repos.yum_config.compose_repos as compose_repos
|
||||
repo_obj = compose_repos.TripleOYumComposeRepoConfig(
|
||||
args.compose_url,
|
||||
args.release,
|
||||
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,
|
||||
override_repos=args.disable_conflicting)
|
||||
|
|
|
@ -18,8 +18,6 @@ import logging
|
|||
import json
|
||||
import os
|
||||
import re
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
from .constants import (
|
||||
YUM_REPO_DIR,
|
||||
|
@ -44,7 +42,8 @@ __metaclass__ = type
|
|||
class TripleOYumComposeRepoConfig(TripleOYumConfig):
|
||||
"""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
|
||||
self.arch = arch or 'x86_64'
|
||||
|
||||
|
@ -80,11 +79,13 @@ class TripleOYumComposeRepoConfig(TripleOYumConfig):
|
|||
super(TripleOYumComposeRepoConfig, self).__init__(
|
||||
valid_options=YUM_REPO_SUPPORTED_OPTIONS,
|
||||
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):
|
||||
"""Retrieve compose info for a provided compose-id url."""
|
||||
# NOTE(dviroel): works for both centos 8 and 9
|
||||
import urllib.request
|
||||
try:
|
||||
logging.debug("Retrieving compose info from url: %s",
|
||||
self.compose_info_url)
|
||||
|
@ -179,7 +180,7 @@ class TripleOYumComposeRepoConfig(TripleOYumConfig):
|
|||
def add_section(self, section, add_dict, file_path):
|
||||
# Create a new file if it does not exists
|
||||
if not os.path.isfile(file_path):
|
||||
with open(file_path, '+w'):
|
||||
with open(file_path, 'w+'):
|
||||
pass
|
||||
super(TripleOYumComposeRepoConfig, self).add_section(
|
||||
section, add_dict, file_path)
|
||||
|
|
|
@ -19,14 +19,21 @@ List of options that can be updated for yum repo files.
|
|||
"""
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
YUM_REPO_SUPPORTED_OPTIONS = [
|
||||
'name',
|
||||
'baseurl',
|
||||
'cost',
|
||||
'enabled',
|
||||
'exclude',
|
||||
'excludepkgs',
|
||||
'gpgcheck',
|
||||
'gpgkey',
|
||||
'priority',
|
||||
'exclude',
|
||||
'includepkgs',
|
||||
'metalink',
|
||||
'mirrorlist',
|
||||
'module_hotfixes',
|
||||
'name',
|
||||
'priority'
|
||||
]
|
||||
|
||||
"""
|
||||
|
@ -68,3 +75,12 @@ COMPOSE_REPOS_INFO_PATH = {
|
|||
"centos-stream-8": "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)
|
||||
|
||||
|
||||
import configparser
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from .constants import (
|
||||
|
@ -33,6 +33,54 @@ from .exceptions import (
|
|||
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
|
||||
|
||||
|
@ -43,6 +91,21 @@ def validated_file_path(file_path):
|
|||
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:
|
||||
"""
|
||||
This class is a base class for updating yum configuration files in
|
||||
|
@ -79,7 +142,8 @@ class TripleOYumConfig:
|
|||
logger.addHandler(handler)
|
||||
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
|
||||
information.
|
||||
|
@ -90,10 +154,13 @@ class TripleOYumConfig:
|
|||
for configuration files to be updated.
|
||||
:param: file_extension: File extension to filter configuration files
|
||||
in the search directory.
|
||||
:param environment_file: File to be read before updating environment
|
||||
variables.
|
||||
"""
|
||||
self.dir_path = dir_path
|
||||
self.file_extension = file_extension
|
||||
self.valid_options = valid_options
|
||||
self.env_file = environment_file
|
||||
|
||||
# Sanity checks
|
||||
if dir_path:
|
||||
|
@ -102,6 +169,9 @@ class TripleOYumConfig:
|
|||
'provided path.').format(dir_path)
|
||||
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):
|
||||
"""Reads a configuration file.
|
||||
|
||||
|
@ -109,7 +179,7 @@ class TripleOYumConfig:
|
|||
to fail earlier if the section is not found.
|
||||
:return: a config parser object and the full file path.
|
||||
"""
|
||||
config = configparser.ConfigParser()
|
||||
config = cfg_parser.ConfigParser()
|
||||
file_paths = [file_path]
|
||||
if self.dir_path:
|
||||
# if dir_path is configured, we can search for filename there
|
||||
|
@ -127,7 +197,7 @@ class TripleOYumConfig:
|
|||
|
||||
try:
|
||||
config.read(valid_file_path)
|
||||
except configparser.Error:
|
||||
except cfg_parser.Error:
|
||||
msg = 'Unable to parse configuration file {0}.'.format(
|
||||
valid_file_path)
|
||||
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):
|
||||
continue
|
||||
|
||||
tmp_config = configparser.ConfigParser()
|
||||
tmp_config = cfg_parser.ConfigParser()
|
||||
try:
|
||||
tmp_config.read(os.path.join(self.dir_path, file))
|
||||
except configparser.Error:
|
||||
except cfg_parser.Error:
|
||||
continue
|
||||
if section in tmp_config.sections():
|
||||
config_files_path.append(os.path.join(self.dir_path, file))
|
||||
|
@ -195,12 +265,12 @@ class TripleOYumConfig:
|
|||
'section {0}'.format(section))
|
||||
raise TripleOYumConfigNotFound(error_msg=msg)
|
||||
|
||||
for k, v in set_dict.items():
|
||||
set_dict[k] = os.path.expandvars(v)
|
||||
for file in files:
|
||||
config, file = self._read_config_file(file, section=section)
|
||||
# Update configuration file with dict updates
|
||||
config[section].update(set_dict)
|
||||
with open(file, 'w') as f:
|
||||
config.write(f)
|
||||
save_section_to_file(file, config, section, set_dict)
|
||||
|
||||
logging.info("Section '%s' was successfully "
|
||||
"updated.", section)
|
||||
|
@ -213,6 +283,11 @@ class TripleOYumConfig:
|
|||
new section.
|
||||
: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
|
||||
config, file_path = self._read_config_file(file_path=file_path)
|
||||
if section in config.sections():
|
||||
|
@ -220,13 +295,12 @@ class TripleOYumConfig:
|
|||
"file.", section)
|
||||
raise TripleOYumConfigInvalidSection(error_msg=msg)
|
||||
|
||||
for k, v in add_dict.items():
|
||||
add_dict[k] = os.path.expandvars(v)
|
||||
# Add new section
|
||||
config.add_section(section)
|
||||
# Update configuration file with dict updates
|
||||
config[section].update(add_dict)
|
||||
|
||||
with open(file_path, '+w') as file:
|
||||
config.write(file)
|
||||
save_section_to_file(file_path, config, section, add_dict)
|
||||
|
||||
logging.info("Section '%s' was successfully "
|
||||
"added.", section)
|
||||
|
@ -245,10 +319,7 @@ class TripleOYumConfig:
|
|||
|
||||
config, file_path = self._read_config_file(file_path)
|
||||
for section in config.sections():
|
||||
config[section].update(set_dict)
|
||||
|
||||
with open(file_path, '+w') as file:
|
||||
config.write(file)
|
||||
save_section_to_file(file_path, config, section, set_dict)
|
||||
|
||||
logging.info("All sections for '%s' were successfully "
|
||||
"updated.", file_path)
|
||||
|
@ -257,13 +328,14 @@ class TripleOYumConfig:
|
|||
class TripleOYumRepoConfig(TripleOYumConfig):
|
||||
"""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
|
||||
|
||||
super(TripleOYumRepoConfig, self).__init__(
|
||||
valid_options=YUM_REPO_SUPPORTED_OPTIONS,
|
||||
dir_path=conf_dir_path,
|
||||
file_extension=YUM_REPO_FILE_EXTENSION)
|
||||
file_extension=YUM_REPO_FILE_EXTENSION,
|
||||
environment_file=environment_file)
|
||||
|
||||
def update_section(
|
||||
self, section, set_dict=None, file_path=None, enabled=None):
|
||||
|
@ -274,11 +346,36 @@ class TripleOYumRepoConfig(TripleOYumConfig):
|
|||
super(TripleOYumRepoConfig, self).update_section(
|
||||
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):
|
||||
"""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
|
||||
logging.info("Using '%s' as yum global configuration "
|
||||
"file.", self.conf_file_path)
|
||||
|
@ -290,13 +387,14 @@ class TripleOYumGlobalConfig(TripleOYumConfig):
|
|||
# create it. If the user specify another conf file that doesn't
|
||||
# exists, the operation will fail.
|
||||
if not os.path.isfile(self.conf_file_path):
|
||||
config = configparser.ConfigParser()
|
||||
config = cfg_parser.ConfigParser()
|
||||
config.read(self.conf_file_path)
|
||||
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)
|
||||
|
||||
super(TripleOYumGlobalConfig, self).__init__()
|
||||
super(TripleOYumGlobalConfig, self).__init__(
|
||||
environment_file=environment_file)
|
||||
|
||||
def update_section(self, section, set_dict, file_path=None):
|
||||
super(TripleOYumGlobalConfig, self).update_section(
|
||||
|
|
|
@ -66,6 +66,11 @@ options:
|
|||
file to be changed.
|
||||
type: path
|
||||
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:
|
||||
description:
|
||||
- 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
|
||||
become: true
|
||||
become_user: root
|
||||
tripleo_yup_config:
|
||||
tripleo_yum_config:
|
||||
compose_url: https://composes.centos.org/latest-CentOS-Stream-8/compose/
|
||||
centos_release: centos-stream-8
|
||||
variants:
|
||||
|
@ -165,6 +170,7 @@ EXAMPLES = r'''
|
|||
|
||||
RETURN = r''' # '''
|
||||
|
||||
from ansible.module_utils import six # noqa: E402
|
||||
from ansible.module_utils.basic import AnsibleModule # noqa: E402
|
||||
|
||||
|
||||
|
@ -172,10 +178,13 @@ def run_module():
|
|||
try:
|
||||
import ansible_collections.tripleo.repos.plugins.module_utils. \
|
||||
tripleo_repos.yum_config.constants as const
|
||||
import ansible_collections.tripleo.repos.plugins.module_utils. \
|
||||
tripleo_repos.yum_config.utils as utils
|
||||
except ImportError:
|
||||
import tripleo_repos.yum_config.constants as const
|
||||
# define available arguments/parameters a user can pass to the module
|
||||
supported_config_types = ['repo', 'module', 'global',
|
||||
import tripleo_repos.yum_config.utils as utils
|
||||
|
||||
supported_config_types = ['repo', 'global', 'module',
|
||||
'enable-compose-repos']
|
||||
supported_module_operations = ['install', 'remove', 'reset']
|
||||
module_args = dict(
|
||||
|
@ -188,6 +197,7 @@ def run_module():
|
|||
set_options=dict(type='dict', default={}),
|
||||
file_path=dict(type='path'),
|
||||
dir_path=dict(type='path', default=const.YUM_REPO_DIR),
|
||||
environment_file=dict(type='path'),
|
||||
compose_url=dict(type='str'),
|
||||
centos_release=dict(type='str',
|
||||
choices=const.COMPOSE_REPOS_RELEASES),
|
||||
|
@ -199,17 +209,37 @@ def run_module():
|
|||
disable_repos=dict(type='list', default=[],
|
||||
elements='str'),
|
||||
)
|
||||
required_if_params = [
|
||||
["type", "repo", ["name"]],
|
||||
["type", "module", ["name"]],
|
||||
["type", "enable-compose-repos", ["compose_url"]]
|
||||
]
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
required_if=[
|
||||
["type", "repo", ["name"]],
|
||||
["type", "module", ["name"]],
|
||||
["type", "enable-compose-repos", ["compose_url"]],
|
||||
],
|
||||
required_if=required_if_params,
|
||||
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.
|
||||
# List of elements will be converted to a comma-separated list
|
||||
m_set_opts = module.params.get('set_options')
|
||||
|
@ -223,33 +253,41 @@ def run_module():
|
|||
# Module execution
|
||||
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.\
|
||||
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:
|
||||
import tripleo_repos.yum_config.dnf_manager as dnf_mgr
|
||||
import tripleo_repos.yum_config.yum_config as cfg
|
||||
import tripleo_repos.yum_config.compose_repos as repos
|
||||
|
||||
if module.params['type'] == 'repo':
|
||||
config_obj = cfg.TripleOYumRepoConfig(
|
||||
dir_path=module.params['dir_path'])
|
||||
config_obj.update_section(
|
||||
dir_path=module.params['dir_path'],
|
||||
environment_file=module.params['environment_file'])
|
||||
config_obj.add_or_update_section(
|
||||
module.params['name'],
|
||||
m_set_opts,
|
||||
set_dict=m_set_opts,
|
||||
file_path=module.params['file_path'],
|
||||
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':
|
||||
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
|
||||
repo_obj = repos.TripleOYumComposeRepoConfig(
|
||||
module.params['compose_url'],
|
||||
module.params['centos_release'],
|
||||
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
|
||||
repo_obj.enable_compose_repos(
|
||||
variants=module.params['variants'],
|
||||
|
@ -259,6 +297,12 @@ def run_module():
|
|||
repo_obj.update_all_sections(file, enabled=False)
|
||||
|
||||
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()
|
||||
if module.params['enabled']:
|
||||
dnf_mod_mgr.enable_module(module.params['name'],
|
||||
|
@ -275,11 +319,6 @@ def run_module():
|
|||
stream=module.params['stream'],
|
||||
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:
|
||||
module.fail_json(msg=str(exc))
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ FAKE_SET_DICT = {
|
|||
FAKE_COMPOSE_URL = (
|
||||
'https://composes.centos.org/fake-CentOS-Stream/compose/')
|
||||
FAKE_REPO_PATH = '/etc/yum.repos.d/fake.repo'
|
||||
FAKE_RELEASE_NAME = 'fake_release'
|
||||
|
||||
FAKE_COMPOSE_INFO = {
|
||||
"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):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FakeConfigParser, self).__init__(*args, **kwargs)
|
||||
self.__dict__ = self
|
||||
|
||||
def write(self, file):
|
||||
def write(self, file, space_around_delimiters=False):
|
||||
pass
|
||||
|
||||
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.constants as const
|
||||
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
|
||||
|
||||
|
||||
|
@ -44,13 +45,19 @@ class TestTripleoYumConfigBase(unittest.TestCase):
|
|||
@ddt.ddt
|
||||
class TestTripleoYumConfigMain(TestTripleoYumConfigBase):
|
||||
"""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):
|
||||
sys.argv[1:] = ['repo', 'fake_repo', '--enable',
|
||||
'--set-opts', 'key1=value1', 'key2=value2',
|
||||
'--config-file-path', fakes.FAKE_FILE_PATH]
|
||||
|
||||
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(
|
||||
yum_cfg, 'TripleOYumRepoConfig',
|
||||
mock.Mock(return_value=yum_repo_obj))
|
||||
|
@ -58,10 +65,11 @@ class TestTripleoYumConfigMain(TestTripleoYumConfigBase):
|
|||
main.main()
|
||||
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(
|
||||
'fake_repo', expected_dict, file_path=fakes.FAKE_FILE_PATH,
|
||||
enabled=True)
|
||||
'fake_repo', set_dict=expected_dict,
|
||||
file_path=fakes.FAKE_FILE_PATH, enabled=True)
|
||||
|
||||
@ddt.data('enable', 'disable', 'reset', 'install', 'remove')
|
||||
def test_main_module(self, operation):
|
||||
|
@ -92,7 +100,8 @@ class TestTripleoYumConfigMain(TestTripleoYumConfigBase):
|
|||
main.main()
|
||||
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)
|
||||
|
||||
def test_main_no_command(self):
|
||||
|
@ -143,9 +152,20 @@ class TestTripleoYumConfigMain(TestTripleoYumConfigBase):
|
|||
fakes.FAKE_COMPOSE_URL,
|
||||
const.COMPOSE_REPOS_RELEASES[0],
|
||||
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(
|
||||
variants=['fake_variant'], override_repos=False)
|
||||
mock_update_all.assert_called_once_with(
|
||||
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 ddt
|
||||
import os
|
||||
import subprocess
|
||||
from unittest import mock
|
||||
|
||||
from . import fakes
|
||||
|
@ -226,17 +227,44 @@ class TestTripleOYumConfig(test_main.TestTripleoYumConfigBase):
|
|||
|
||||
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
|
||||
class TestTripleOYumRepoConfig(test_main.TestTripleoYumConfigBase):
|
||||
"""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)
|
||||
def test_yum_repo_config_update_section(self, enable):
|
||||
self.mock_object(os.path, 'isfile')
|
||||
self.mock_object(os, 'access')
|
||||
self.mock_object(os.path, 'isdir')
|
||||
cfg_obj = yum_cfg.TripleOYumRepoConfig()
|
||||
|
||||
mock_update = self.mock_object(yum_cfg.TripleOYumConfig,
|
||||
'update_section')
|
||||
|
@ -246,13 +274,78 @@ class TestTripleOYumRepoConfig(test_main.TestTripleoYumConfigBase):
|
|||
if enable is not None:
|
||||
expected_updates['enabled'] = '1' if enable else '0'
|
||||
|
||||
cfg_obj.update_section(fakes.FAKE_SECTION1, set_dict=updates,
|
||||
self.config_obj.update_section(
|
||||
fakes.FAKE_SECTION1, set_dict=updates,
|
||||
file_path=fakes.FAKE_FILE_PATH, enabled=enable)
|
||||
|
||||
mock_update.assert_called_once_with(fakes.FAKE_SECTION1,
|
||||
expected_updates,
|
||||
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
|
||||
class TestTripleOYumGlobalConfig(test_main.TestTripleoYumConfigBase):
|
||||
|
|
Loading…
Reference in New Issue