tripleo-heat-templates/tools/render-ansible-tasks.py

129 lines
5.1 KiB
Python
Executable File

#!/usr/bin/env python3
#
# Copyright 2019 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.
#
import argparse
import errno
import json
import os
import sys
import yaml
import yaql
def parse_opts(argv):
parser = argparse.ArgumentParser(
description='Render the Ansible tasks based in the role and the tags selected.'
'Those tasks can be used for debugging or linting purposes.')
subp = parser.add_mutually_exclusive_group(required=True)
parser.add_argument('--output', required=True, metavar='<tasks directory output>',
help="The folder to store the rendered tasks",
)
parser.add_argument('--ansible-tasks', nargs="+", required=True,
metavar='<ansible tasks to be rendered>',
help='THT tags to filter the Ansible rendering '
'i.e. update_tasks')
subp.add_argument('--roles-list', nargs="+", metavar='<list of roles to render>',
help='Composable roles to filter the Ansible rendering '
'i.e. Controller Compute')
subp.add_argument('--all', action='store_true',
help='Process all services in the resource registry at once, '
'this allows to test all services templates avoiding '
'reading and generating all the files.')
opts = parser.parse_args(argv[1:])
return opts
def main():
opts = parse_opts(sys.argv)
engine = yaql.factory.YaqlFactory().create()
output = opts.output
# We open the resource registry once
resource_registry = "./overcloud-resource-registry-puppet.yaml"
resource_reg = yaml.load(open(os.path.join(resource_registry), 'r'))
if (opts.all):
# This means we will parse all the services defined
# by default in the resource registry
roles_list = ["overcloud-resource-registry-puppet"]
else:
roles_list = opts.roles_list
for role in roles_list:
# We open the role file only once.
if (opts.all):
# The service definition will be the same resource registry
role_resources = resource_reg
else:
role_resources = yaml.load(open(os.path.join("./roles/", role + ".yaml"), 'r'))
for section_task in opts.ansible_tasks:
if(opts.all):
# We get all the services in the resource_registry section
expression = engine(
"$.resource_registry"
)
else:
expression = engine(
"$.ServicesDefault.flatten().distinct()"
)
heat_resources = expression.evaluate(data=role_resources)
role_ansible_tasks = []
for resource in heat_resources:
if(opts.all):
# If we use the resource registry as the source of the
# data we need to split the service name of the
# service config definition
resource = resource.split(' ')[0]
expression = engine(
"$.resource_registry.get('" + resource + "')"
)
config_file = expression.evaluate(data=resource_reg)
if(config_file is not None):
if('::' in config_file):
print("This is a nested Heat resource")
else:
data_source = yaml.load(open("./" + config_file, 'r'))
expression = engine(
"$.outputs.role_data.value.get(" + section_task + ").flatten().distinct()"
)
try:
ansible_tasks = expression.evaluate(data=data_source)
print(ansible_tasks)
role_ansible_tasks = role_ansible_tasks + ansible_tasks
except Exception:
print("There are no tasks in the configuration file")
if (role_ansible_tasks != []):
tasks_output_file = os.path.join(output, role + "_" + section_task + ".yml")
if not os.path.exists(os.path.dirname(tasks_output_file)):
try:
os.makedirs(os.path.dirname(tasks_output_file))
except OSError as exc:
if exc.errno != errno.EEXIST:
raise
save = open(tasks_output_file, 'w+')
yaml.dump(yaml.load(json.dumps(role_ansible_tasks)), save, default_flow_style=False)
if __name__ == '__main__':
main()