#!/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. from __future__ import absolute_import, division, print_function __metaclass__ = type from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.parsing.convert_bool import boolean import glob import json import os import yaml ANSIBLE_METADATA = { 'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community' } DOCUMENTATION = """ --- module: container_config_data author: - Emilien Macchi version_added: '2.8' short_description: Generates a dictionary which contains all container configs notes: [] description: - This module reads container configs in JSON files and generate a dictionary which later will be used to manage the containers. options: config_path: description: - The path of a directory or a file where the JSON files are. This parameter is required. required: True type: str config_pattern: description: - Search pattern to find JSON files. default: '*.json' required: False type: str config_overrides: description: - Allows to override any container configuration which will take precedence over the JSON files. default: {} required: False type: dict debug: description: - Whether or not debug is enabled. default: False required: False type: bool """ EXAMPLES = """ - name: Generate containers configs data container_config_data: config_path: /var/lib/tripleo-config/container-startup-config/step_1 - name: Generate containers configs data for HAproxy and override image container_config_data: config_path: /var/lib/tripleo-config/container-startup-config/step_1 config_pattern: 'haproxy.json' config_overrides: haproxy: image: my-registry.io/tripleo/haproxy:mytag """ RETURN = """ configs: description: - Dictionary with container configs ready to be consumed by tripleo_container_manage role. returned: always type: dict """ class ContainerConfigDataManager(object): """Notes about this module. It will generates a dictionary which contains all container configs, later consumed by tripleo_container_manage role. """ def __init__(self, module, results): self.module = module self.results = results # parse args args = self.module.params # Set parameters config_path = args['config_path'] config_pattern = args['config_pattern'] config_overrides = args['config_overrides'] self.debug = args['debug'] # Generate dict from JSON files that match search pattern if os.path.exists(config_path): matched_configs = glob.glob(os.path.join(config_path, config_pattern)) 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) # Returns data self.module.exit_json(**self.results) def _merge_with_overrides(self, config, merge_with=None): """Merge config with a given dict of overrides. :param config: dictionary of configs :param merge_with: dictionary of overrides :return: dict """ merged_dict = config if merge_with is None: merge_with = {} for k in merge_with.keys(): if k in config: for mk, mv in merge_with[k].items(): if self.debug: self.module.debug('Override found for {}: {} will be ' 'set to {}'.format(k, mk, mv)) merged_dict[k][mk] = mv break return merged_dict def _slurp(self, path): """Slurps a file and return its content. :param path: string :returns: string """ if os.path.exists(path): f = open(path, 'r') return f.read() else: self.module.warn('{} was not found.'.format(path)) return '' def main(): module = AnsibleModule( argument_spec=yaml.safe_load(DOCUMENTATION)['options'], supports_check_mode=True, ) results = dict( changed=False, configs={} ) ContainerConfigDataManager(module, results) if __name__ == '__main__': main()