diff --git a/tripleo_ansible/ansible_plugins/modules/container_config_data.py b/tripleo_ansible/ansible_plugins/modules/container_config_data.py index fcd72771e..468a8f319 100644 --- a/tripleo_ansible/ansible_plugins/modules/container_config_data.py +++ b/tripleo_ansible/ansible_plugins/modules/container_config_data.py @@ -118,22 +118,22 @@ class ContainerConfigDataManager(object): if os.path.exists(config_path): matched_configs = glob.glob(os.path.join(config_path, config_pattern)) + config_dict = {} + for mc in matched_configs: + name = os.path.splitext(os.path.basename(mc))[0] + config = json.loads(self._slurp(mc)) + if self.debug: + self.module.debug('Config found for {}: {}'.format(name, + config)) + config_dict.update({name: config}) + + # Merge the config dict with given overrides + self.results['configs'] = self._merge_with_overrides( + config_dict, config_overrides) else: - self.module.fail_json( - msg='{} does not exists'.format(config_path)) - - config_dict = {} - for mc in matched_configs: - name = os.path.splitext(os.path.basename(mc))[0] - config = json.loads(self._slurp(mc)) - if self.debug: - self.module.debug('Config found for {}: {}'.format(name, - config)) - config_dict.update({name: config}) - - # Merge the config dict with given overrides - self.results['configs'] = self._merge_with_overrides(config_dict, - config_overrides) + self.module.debug( + msg='{} does not exists, skipping step'.format(config_path)) + self.results['configs'] = {} # Returns data self.module.exit_json(**self.results) diff --git a/tripleo_ansible/ansible_plugins/modules/container_startup_config.py b/tripleo_ansible/ansible_plugins/modules/container_startup_config.py new file mode 100644 index 000000000..cb4ed0740 --- /dev/null +++ b/tripleo_ansible/ansible_plugins/modules/container_startup_config.py @@ -0,0 +1,142 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# 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 + +import json +import os +import shutil +import yaml + +from ansible.module_utils.basic import AnsibleModule + +DOCUMENTATION = """ +--- +module: container_startup_config +author: + - "TripleO team" +version_added: '2.9' +short_description: Generate startup containers configs +notes: [] +description: + - It will generate container startup configs that will be consumed by the + tripleo-container-manage role that is using podman_container module. +requirements: + - None +options: + config_base_dir: + description: + - Config base directory + type: str + default: '/var/lib/tripleo-config/container-startup-config' + config_data: + description: + - Dictionary of container configs data + type: dict + required: true +""" + +EXAMPLES = """ +- name: Generate startup container config for all the steps + container_startup_config: + config_data: + step_1: + haproxy: + image: docker.io/haproxy + memcached: + image: docker.io/memcached + step_2: + mysql: + image: docker.io/mysql +""" + + +class ContainerStartupManager: + """Class for container_startup_config module.""" + + def __init__(self, module, results): + + super(ContainerStartupManager, self).__init__() + self.module = module + self.results = results + + # parse args + args = self.module.params + + # Set parameters + self.config_base_dir = args['config_base_dir'] + self.config_data = args['config_data'] + + # Cleanup old configs created by previous releases + self._cleanup_old_configs() + + # Create config_base_dir + if not os.path.exists(self.config_base_dir): + os.makedirs(self.config_base_dir) + os.chmod(self.config_base_dir, 0o600) + self.results['changed'] = True + + # Generate the container configs per step + for step, step_config in self.config_data.items(): + step_dir = os.path.join(self.config_base_dir, step) + # Note: it'll cleanup old configs before creating new ones. + # TODO(emilien) add idempotency so we only remove the needed files + self._recreate_dir(step_dir) + for container, container_config in step_config.items(): + container_config_path = os.path.join(self.config_base_dir, + step, container + '.json') + self._create_config(container_config_path, container_config) + + self.module.exit_json(**self.results) + + def _recreate_dir(self, path): + """Creates a directory. + + :param path: string + """ + shutil.rmtree(path, ignore_errors=True) + os.makedirs(path) + + def _create_config(self, path, config): + """Update a container config. + + :param path: string + :param config: string + """ + with open(path, "wb") as config_file: + config_file.write(json.dumps(config, indent=2).encode('utf-8')) + os.chmod(path, 0o600) + self.results['changed'] = True + + def _cleanup_old_configs(self): + """Cleanup old container configurations and directories. + """ + # TODO(emilien) remove old .json in /var/lib/tripleo-config/*.json + + +def main(): + module = AnsibleModule( + argument_spec=yaml.safe_load(DOCUMENTATION)['options'], + supports_check_mode=True, + ) + results = dict( + changed=False + ) + ContainerStartupManager(module, results) + + +if __name__ == '__main__': + main() diff --git a/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/container-configs.yml b/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/container-configs.yml new file mode 100644 index 000000000..9cbc04de4 --- /dev/null +++ b/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/container-configs.yml @@ -0,0 +1,16 @@ +--- +step_1: + haproxy: + environment: + KOLLA_CONFIG_STRATEGY: COPY_ALWAYS + image: 192.168.24.1:8787/myregistry/openstack-haproxy:latest + keepalived: + image: 192.168.24.1:8787/myregistry/openstack-keepalived:latest +step_2: + mysql: + image: 192.168.24.1:8787/myregistry/openstack-mysql:latest + swift: + image: 192.168.24.1:8787/myregistry/openstack-swift:latest +step_3: + keystone: + image: 192.168.24.1:8787/myregistry/openstack-keystone:latest diff --git a/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/converge.yml b/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/converge.yml new file mode 100644 index 000000000..80f884fdd --- /dev/null +++ b/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/converge.yml @@ -0,0 +1,26 @@ +--- +- name: Converge + hosts: all + become: true + tasks: + - name: Create temporary for container configs + tempfile: + state: directory + suffix: container_startup_config_tmp + register: container_startup_config_tmp_dir + - name: Generate container startup configs + container_startup_config: + config_data: "{{ lookup('file', playbook_dir + '/container-configs.yml', errors='ignore') | default({}, True) | from_yaml }}" + config_base_dir: "{{ container_startup_config_tmp_dir.path }}" + - name: Check that HAproxy container configuration file was created + stat: + path: "{{ container_startup_config_tmp_dir.path }}/step_1/haproxy.json" + register: st_haproxy + failed_when: + - not st_haproxy.stat.exists + - name: Check that HAproxy container configuration is correct + slurp: + src: "{{ container_startup_config_tmp_dir.path }}/step_1/haproxy.json" + register: slurp_haproxy + failed_when: + - ('openstack-haproxy' not in slurp_haproxy['content']|b64decode) diff --git a/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/molecule.yml b/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/molecule.yml new file mode 100644 index 000000000..9cd87438e --- /dev/null +++ b/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/molecule.yml @@ -0,0 +1,50 @@ +--- +driver: + name: delegated + options: + managed: false + login_cmd_template: >- + ssh + -o UserKnownHostsFile=/dev/null + -o StrictHostKeyChecking=no + -o Compression=no + -o TCPKeepAlive=yes + -o VerifyHostKeyDNS=no + -o ForwardX11=no + -o ForwardAgent=no + {instance} + ansible_connection_options: + ansible_connection: ssh + +log: true + +platforms: + - name: instance + +provisioner: + name: ansible + config_options: + defaults: + fact_caching: jsonfile + fact_caching_connection: /tmp/molecule/facts + inventory: + hosts: + all: + hosts: + instance: + ansible_host: localhost + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_ROLES_PATH: "${ANSIBLE_ROLES_PATH:-/usr/share/ansible/roles}:${HOME}/zuul-jobs/roles" + ANSIBLE_LIBRARY: "${ANSIBLE_LIBRARY:-/usr/share/ansible/plugins/modules}" + ANSIBLE_FILTER_PLUGINS: "${ANSIBLE_FILTER_PLUGINS:-/usr/share/ansible/plugins/filter}" + +scenario: + name: container_startup_config + test_sequence: + - prepare + - converge + +verifier: + name: testinfra diff --git a/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/prepare.yml b/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/prepare.yml new file mode 100644 index 000000000..805f61ee9 --- /dev/null +++ b/tripleo_ansible/ansible_plugins/tests/molecule/container_startup_config/prepare.yml @@ -0,0 +1,20 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Prepare + hosts: all + roles: + - role: test_deps diff --git a/tripleo_ansible/roles/tripleo_container_manage/tasks/main.yml b/tripleo_ansible/roles/tripleo_container_manage/tasks/main.yml index a773fe0e7..10d1b2d03 100644 --- a/tripleo_ansible/roles/tripleo_container_manage/tasks/main.yml +++ b/tripleo_ansible/roles/tripleo_container_manage/tasks/main.yml @@ -70,6 +70,7 @@ - name: "Manage containers from {{ tripleo_container_manage_config }}" when: + - (all_containers_hash|length) > 0 - tripleo_container_manage_cli == 'podman' become: true block: diff --git a/zuul.d/molecule.yaml b/zuul.d/molecule.yaml index ff3125100..3ce30c558 100644 --- a/zuul.d/molecule.yaml +++ b/zuul.d/molecule.yaml @@ -248,6 +248,7 @@ - ^tripleo_ansible/ansible_plugins/filter/helpers.py$ - ^tripleo_ansible/ansible_plugins/modules/container_config_data.py$ - ^tripleo_ansible/ansible_plugins/modules/container_puppet_config.py$ + - ^tripleo_ansible/ansible_plugins/modules/container_startup_config.py$ - ^tripleo_ansible/ansible_plugins/modules/podman_container.py$ - ^tripleo_ansible/ansible_plugins/modules/podman_container_info.py$ name: tripleo-ansible-centos-8-molecule-tripleo_container_manage