2 # Licensed under the Apache License, Version 2.0 (the "License"); you may
3 # not use this file except in compliance with the License. You may obtain
4 # a copy of the License at
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11 # License for the specific language governing permissions and limitations
24 parser = argparse.ArgumentParser(
25 description='Configure host network interfaces using a JSON'
26 ' config file format.')
27 parser.add_argument('-p', '--base_path', metavar='BASE_PATH',
28 help="""base path of templates to process.""",
30 parser.add_argument('-r', '--roles-data', metavar='ROLES_DATA',
31 help="""relative path to the roles_data.yaml file.""",
32 default='roles_data.yaml')
33 parser.add_argument('--safe',
35 help="""Enable safe mode (do not overwrite files).""",
37 parser.add_argument('-o', '--output-dir', metavar='OUTPUT_DIR',
38 help="""Output dir for all the templates""",
40 opts = parser.parse_args(argv[1:])
45 def _j2_render_to_file(j2_template, j2_data, outfile_name=None,
47 yaml_f = outfile_name or j2_template.replace('.j2.yaml', '.yaml')
48 print('rendering j2 template to file: %s' % outfile_name)
50 if not overwrite and os.path.exists(outfile_name):
51 print('ERROR: path already exists for file: %s' % outfile_name)
55 # Render the j2 template
56 template = jinja2.Environment().from_string(j2_template)
57 r_template = template.render(**j2_data)
58 except jinja2.exceptions.TemplateError as ex:
59 error_msg = ("Error rendering template %s : %s"
60 % (yaml_f, six.text_type(ex)))
62 raise Exception(error_msg)
63 with open(outfile_name, 'w') as out_f:
64 out_f.write(r_template)
67 def process_templates(template_path, role_data_path, output_dir, overwrite):
69 with open(role_data_path) as role_data_file:
70 role_data = yaml.safe_load(role_data_file)
72 j2_excludes_path = os.path.join(template_path, 'j2_excludes.yaml')
73 with open(j2_excludes_path) as role_data_file:
74 j2_excludes = yaml.safe_load(role_data_file)
76 if output_dir and not os.path.isdir(output_dir):
77 if os.path.exists(output_dir):
78 raise RuntimeError('Output dir %s is not a directory' % output_dir)
81 role_names = [r.get('name') for r in role_data]
84 r_map[r.get('name')] = r
85 excl_templates = ['%s/%s' % (template_path, e)
86 for e in j2_excludes.get('name')]
88 if os.path.isdir(template_path):
89 for subdir, dirs, files in os.walk(template_path):
91 # NOTE(flaper87): Ignore hidden dirs as we don't
92 # generate templates for those.
93 # Note the slice assigment for `dirs` is necessary
94 # because we need to modify the *elements* in the
95 # dirs list rather than the reference to the list.
96 # This way we'll make sure os.walk will iterate over
97 # the shrunk list. os.walk doesn't have an API for
98 # filtering dirs at this point.
99 dirs[:] = [d for d in dirs if not d[0] == '.']
100 files = [f for f in files if not f[0] == '.']
102 # NOTE(flaper87): We could have used shutil.copytree
103 # but it requires the dst dir to not be present. This
104 # approach is safer as it doesn't require us to delete
105 # the output_dir in advance and it allows for running
106 # the command multiple times with the same output_dir.
109 out_dir = os.path.join(output_dir, subdir)
110 if not os.path.exists(out_dir):
114 file_path = os.path.join(subdir, f)
115 # We do two templating passes here:
116 # 1. *.role.j2.yaml - we template just the role name
117 # and create multiple files (one per role)
118 # 2. *.j2.yaml - we template with all roles_data,
119 # and create one file common to all roles
120 if f.endswith('.role.j2.yaml'):
121 print("jinja2 rendering role template %s" % f)
122 with open(file_path) as j2_template:
123 template_data = j2_template.read()
124 print("jinja2 rendering roles %s" % ","
126 for role in role_names:
127 j2_data = {'role': role}
128 # (dprince) For the undercloud installer we don't
129 # want to have heat check nova/glance API's
130 if r_map[role].get('disable_constraints', False):
131 j2_data['disable_constraints'] = True
134 os.path.basename(f).replace('.role.j2.yaml',
136 out_f_path = os.path.join(out_dir, out_f)
137 if not (out_f_path in excl_templates):
138 _j2_render_to_file(template_data, j2_data,
139 out_f_path, overwrite)
141 print('skipping rendering of %s' % out_f_path)
142 elif f.endswith('.j2.yaml'):
143 print("jinja2 rendering normal template %s" % f)
144 with open(file_path) as j2_template:
145 template_data = j2_template.read()
146 j2_data = {'roles': role_data}
147 out_f = os.path.basename(f).replace('.j2.yaml', '.yaml')
148 out_f_path = os.path.join(out_dir, out_f)
149 _j2_render_to_file(template_data, j2_data, out_f_path,
152 shutil.copy(os.path.join(subdir, f), out_dir)
155 print('Unexpected argument %s' % template_path)
157 opts = parse_opts(sys.argv)
159 role_data_path = os.path.join(opts.base_path, opts.roles_data)
161 process_templates(opts.base_path, role_data_path, opts.output_dir, (not opts.safe))