From 6a24ca732529b282315da114273f6f79001d0a44 Mon Sep 17 00:00:00 2001 From: Alex Schultz Date: Thu, 17 Jun 2021 13:28:41 +0000 Subject: [PATCH] Revert "Container manage module" This reverts commit 22bbe1311094be600b9fed426f1ee0a983b8e111. This appears to have broken updates. Let's revert for now. Change-Id: I680b38643151a2a16205e15edd3ea8703214a2d8 Related-Bug: #1932261 --- .../modules/container_puppet_config.py | 8 +- .../modules/tripleo_container_manage.py | 368 ------------------ .../molecule/default/converge.yml | 2 +- .../tripleo_container_manage/tasks/create.yml | 13 +- 4 files changed, 11 insertions(+), 380 deletions(-) delete mode 100644 tripleo_ansible/ansible_plugins/modules/tripleo_container_manage.py diff --git a/tripleo_ansible/ansible_plugins/modules/container_puppet_config.py b/tripleo_ansible/ansible_plugins/modules/container_puppet_config.py index 71251aad8..cc1a661d3 100644 --- a/tripleo_ansible/ansible_plugins/modules/container_puppet_config.py +++ b/tripleo_ansible/ansible_plugins/modules/container_puppet_config.py @@ -266,10 +266,8 @@ class ContainerPuppetManager: default_data = { # the security_opt can be removed once we properly address: # https://bugs.launchpad.net/tripleo/+bug/1864501 - 'security_opt': ['label=disable'], + 'security_opt': 'label=disable', 'user': 0, - # container-puppet shouldn't detach - 'detach': False, 'entrypoint': CONTAINER_ENTRYPOINT, 'environment': self._get_environment_config() } @@ -281,10 +279,10 @@ class ContainerPuppetManager: volumes += ['/etc/puppet/check-mode:' '/tmp/puppet-check-mode:ro'] if self.net_host: - cdata['net'] = ['host'] + cdata['net'] = 'host' volumes += ['/etc/hosts:/etc/hosts:ro'] else: - cdata['net'] = ['none'] + cdata['net'] = 'none' cdata['environment']['PUPPET_TAGS'] = ( self._get_puppet_tags(config)) diff --git a/tripleo_ansible/ansible_plugins/modules/tripleo_container_manage.py b/tripleo_ansible/ansible_plugins/modules/tripleo_container_manage.py deleted file mode 100644 index ff9d0de61..000000000 --- a/tripleo_ansible/ansible_plugins/modules/tripleo_container_manage.py +++ /dev/null @@ -1,368 +0,0 @@ -#!/usr/bin/python -# Copyright 2020 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -__metaclass__ = type - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.parsing.convert_bool import boolean - -import glob -import os -import yaml -import json - -from concurrent.futures import ThreadPoolExecutor - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community' -} - -DOCUMENTATION = """ ---- -module: tripleo_container_manage -author: - - "Alex Schultz (@mwhahaha)" -version_added: '2.9' -short_description: Create containers from a set of json configurations -notes: [] -description: - - Generate puppet containers configs -requirements: - - None -options: - config_id: - description: - - Config id for the label - type: str - required: True - config_dir: - description: - - Path to the json container definitions - type: str - required: True - config_patterns: - description: - - Glob for configuration files - type: str - default: "*.json" - config_overrides: - description: - - Allows to override any container configuration which will take - precedence over the JSON files. - default: {} - required: False - type: dict - log_base_path: - description: - - Log base path directory - type: str - default: '/var/log/containers/stdouts' - concurrency: - description: - - Number of podman actions to run at the same time - type: int - default: 1 - debug: - description: - - Enable debug - type: bool - default: False -""" - -EXAMPLES = """ -- name: Run containers - tripleo_container_manage - config_id: tripleo_step1 - config_dir: /var/lib/tripleo-config/container-startup-config/step_1 -""" - - -from ansible_collections.containers.podman.plugins.module_utils.podman.podman_container_lib import PodmanManager, ARGUMENTS_SPEC_CONTAINER # noqa: F402 - - -class ExecFailure(Exception): - def __init__(self, msg, stdout=None, stderr=None): - super().__init__(msg) - self.msg = msg - self.stdout = stdout - self.stderr = stderr - - def __str__(self): - return f"ERROR: {self.msg}\nstderr: {self.stderr}" - - -class TripleoContainerManage: - """Notes about this module. - - It will generate container config that will be consumed by the - tripleo-container-manage role that is using podman_container module. - """ - - def __init__(self, module, results): - self.module = module - self.results = results - - # parse args - args = self.module.params - - # Set parameters - self.concurrency = args.get('concurrency', 4) - self.config_id = args.get('config_id') - self.config_dir = args.get('config_dir') - self.config_patterns = args.get('config_patterns') - self.config_overrides = args['config_overrides'] - self.log_base_path = args.get('log_base_path') - self.debug = args.get('debug') - - self.run() - - self.module.exit_json(**self.results) - - # container_config_data.py without overrides - def _get_configs(self): - configs = {} - if not os.path.exists(self.config_dir): - self.module.warn('Configuration directory does not exist ' - f'{self.config_dir}') - return configs - - matches = glob.glob(os.path.join(self.config_dir, - self.config_patterns)) - for match in matches: - name = os.path.splitext(os.path.basename(match))[0] - with open(match, 'r') as data: - config = json.loads(data.read()) - if self.debug: - self.module.debug('Config found for {}: {}'.format(name, - config)) - configs.update({name: config}) - - # handle overrides similar to container_config_data - if self.config_overrides: - for k in self.config_overrides.keys(): - if k in configs: - for mk, mv in self.config_overrides[k].items(): - if self.debug: - self.module.debug(f'Override found for {k}: {mk} ' - f'will be set to {mv}') - configs[k][mk] = mv - return configs - - def _get_version(self): - rc, out, err = self.module.run_command(['podman', b'--version']) - if rc != 0 or not out or 'version' not in out: - self.module.fail_json(msg='Can not determine podman version') - return out.split('versio')[1].strip() - - def _container_opts_defaults(self): - default = {} - opts = ARGUMENTS_SPEC_CONTAINER - for k, v in opts.items(): - if 'default' in v: - default[k] = v['default'] - else: - default[k] = None - return default - - def _container_opts_update(self, container_opts): - opts_dict = self._container_opts_defaults() - aliases = {} - for k, v in ARGUMENTS_SPEC_CONTAINER.items(): - if 'aliases' in v: - for alias in v['aliases']: - aliases[alias] = k - for k in list(container_opts): - if k in aliases: - key = aliases[k] - opts_dict[key] = container_opts[k] - container_opts.pop(k) - opts_dict.update(container_opts) - return opts_dict - - def _container_opts_types(self, container_opts): - # convert data types since magic ansible option conversion doesn't - # occur here. - for k, v in container_opts.items(): - if v is None: - continue - if ARGUMENTS_SPEC_CONTAINER.get(k) is None: - if self.debug: - self.module.debug(f"Container opt '{k}' is unknown") - continue - opt_type = ARGUMENTS_SPEC_CONTAINER.get(k).get('type') - if opt_type in ['raw', 'path']: - continue - if not isinstance(v, eval(opt_type)): - if isinstance(v, str) and opt_type == 'list': - container_opts[k] = [v] - elif isinstance(v, str) and opt_type == 'bool': - container_opts[k] = boolean(v) - elif isinstance(v, str) and opt_type == 'int': - container_opts[k] = int(v) - elif isinstance(v, int) and opt_type == 'str': - container_opts[k] = str(v) - else: - raise TypeError(f"Container {container_opts['name']} " - f"option ({k}, {v}) is not " - f"type {opt_type} is {type(v)}") - return container_opts - - def _list_or_dict_arg(self, data, cmd, key, arg): - """Utility to build a command and its argument with list or dict data. - - The key can be a dictionary or a list, the returned arguments will be - a list where each item is the argument name and the item data. - """ - if key not in data: - return - value = data[key] - if isinstance(value, dict): - for k, v in sorted(value.items()): - if v: - cmd.append('%s=%s=%s' % (arg, k, v)) - elif k: - cmd.append('%s=%s' % (arg, k)) - elif isinstance(value, list): - for v in value: - if v: - cmd.append('%s=%s' % (arg, v)) - - def exec_container(self, name, config): - cmd = ['podman', 'exec', f"--user={config.get('user', 'root')}"] - if 'privileged' in config: - cmd.append('--privileged=%s' % str(config['privileged']).lower()) - self._list_or_dict_arg(config, cmd, 'environment', '--env') - cmd.extend(config['command']) - rc, out, err = self.module.run_command(cmd) - if rc != 0: - msg = "Failure running exec '{}'. rc={}, stdout={}, stderr={}".format(name, rc, out, err) - self.module.warn(msg) - return False - return True - - def manage_container(self, name, config): - opts = { - 'name': name, - 'state': "present", - 'label': { - 'config_id': self.config_id, - 'container_name': name, - 'managed_by': 'tripleo_ansible', - 'config_data': config - }, - 'conmon_pidfile': f"/var/run/{name}.pid", - 'debug': self.debug, - 'log_driver': 'k8s-file', - 'log_opt': {"path": f"{self.log_base_path}/{name}.log"}, - } - opts.update(config) - # do horible things to convert THT format to ansible module format - if 'volumes' in opts: - opts['volume'] = opts.pop('volumes') - if 'environment' in opts: - opts['env'] = opts.pop('environment') - if 'healthcheck' in opts and isinstance(opts['healthcheck'], dict): - opts['healthcheck'] = opts['healthcheck'].get('test', None) - if 'check_interval' in opts: - opts['healthcheck_interval'] = opts.pop('check_interval') - if 'remove' in opts: - opts['rm'] = opts.pop('remove') - if 'restart' in opts: - # NOTE(mwhahaha): converation from tripleo format to podman as - # systemd handles this restart config - opts['restart'] = False - if 'stop_grace_period' in opts: - opts['stop_timeout'] = opts.pop('stop_grace_period') - - success = True - try: - container_opts = self._container_opts_update(opts) - container_opts = self._container_opts_types(container_opts) - PodmanManager(self.module, container_opts).execute() - except ExecFailure as e: - print(e) - self.module.warn(str(e)) - success = False - return success - - def run_container(self, data): - name, config = data - action = config.get('action', 'create') - success = False - if action == 'exec': - success = self.exec_container(name, config) - else: - success = self.manage_container(name, config) - return (name, success) - - def check_failures(self, results): - failed = [] - for result in results: - name, res = result - if not res: - failed.append(name) - return failed - - def batch_start_order(self, configs): - data = {} - for k in configs: - start_order = configs[k].get('start_order', 0) - if start_order not in data: - data[start_order] = [] - data[start_order].append((k, configs.get(k))) - return data - - def run(self): - configs = self._get_configs() - # sort configs by start_order - # launch containers? - data = self.batch_start_order(configs) - failed = [] - - def exe_fail_json(**kwargs): - raise ExecFailure(**kwargs) - - # NOTE: fix because PodmanManager calls fail_json directly so we want - # to handle those all at once at the end - orig_fail = self.module.fail_json - self.module.fail_json = exe_fail_json - # loop through keys sorted - for start_order in sorted(data.keys()): - with ThreadPoolExecutor(max_workers=self.concurrency) as exc: - results = exc.map(self.run_container, data[start_order]) - failed.extend(self.check_failures(results)) - self.module.fail_json = orig_fail - - if len(failed) > 0: - self.module.fail_json( - msg='Failed containers: {}'.format(', '.join(failed))) - self.results['changed'] = True - - -def main(): - module = AnsibleModule( - argument_spec=yaml.safe_load(DOCUMENTATION)['options'], - supports_check_mode=True, - ) - results = dict( - changed=False - ) - TripleoContainerManage(module, results) - - -if __name__ == '__main__': - main() diff --git a/tripleo_ansible/roles/tripleo_container_manage/molecule/default/converge.yml b/tripleo_ansible/roles/tripleo_container_manage/molecule/default/converge.yml index a7a3a9874..f7c99236b 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/molecule/default/converge.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/molecule/default/converge.yml @@ -229,7 +229,7 @@ assert: that: - "'fedora:rawhide' in fedora_infos.containers.0.ImageName" - fail_msg: "fedora container has wrong image {{ fedora_infos.containers }}" + fail_msg: 'fedora container has wrong image' success_msg: 'fedora container has the right image' - name: Check if tripleo_fedora systemd service is active command: systemctl is-active --quiet tripleo_fedora diff --git a/tripleo_ansible/roles/tripleo_container_manage/tasks/create.yml b/tripleo_ansible/roles/tripleo_container_manage/tasks/create.yml index 6bac98795..d489e1ff5 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/tasks/create.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/tasks/create.yml @@ -15,12 +15,13 @@ # under the License. - name: "Create containers managed by Podman for {{ tripleo_container_manage_config }}" - tripleo_container_manage: - config_id: "{{ tripleo_container_manage_config_id }}" - config_dir: "{{ tripleo_container_manage_config }}" - config_patterns: "{{ tripleo_container_manage_config_patterns }}" - config_overrides: "{{ tripleo_container_manage_config_overrides }}" - concurrency: "{{ tripleo_container_manage_concurrency }}" + when: + - tripleo_container_manage_cli == 'podman' + include_tasks: podman/start_order.yml + vars: + order: "{{ item.key }}" + data: "{{ item.value }}" + loop: "{{ all_containers_hash | subsort(attribute='start_order', null_value=0) | dict2items | list }}" - name: "Manage container systemd services and cleanup old systemd healthchecks for {{ tripleo_container_manage_config }}" become: true