3 # Copyright 2015 Red Hat Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
23 _PARAM_FORMAT = u""" # %(description)s
24 %(mandatory)s# Type: %(type)s
27 _STATIC_MESSAGE_START = (
28 ' # ******************************************************\n'
29 ' # Static parameters - these are values that must be\n'
30 ' # included in the environment but should not be changed.\n'
31 ' # ******************************************************\n'
33 _STATIC_MESSAGE_END = (' # *********************\n'
34 ' # End static parameters\n'
35 ' # *********************\n'
38 '# *******************************************************************\n'
39 '# This file was created automatically by the sample environment\n'
40 '# generator. Developers should use `tox -e genconfig` to update it.\n'
41 '# Users are recommended to make changes to a copy of the file instead\n'
42 '# of the original, if any customizations are needed.\n'
43 '# *******************************************************************\n'
45 # Certain parameter names can't be changed, but shouldn't be shown because
46 # they are never intended for direct user input.
47 _PRIVATE_OVERRIDES = ['server', 'servers', 'NodeIndex', 'DefaultPasswords']
48 # Hidden params are not included by default when the 'all' option is used,
49 # but can be explicitly included by referencing them in sample_defaults or
50 # static. This allows us to generate sample environments using them when
51 # necessary, but they won't be improperly included by accident.
52 _HIDDEN_PARAMS = ['EndpointMap', 'RoleName', 'RoleParameters',
57 def _create_output_dir(target_file):
59 os.makedirs(os.path.dirname(target_file))
61 if e.errno == errno.EEXIST:
67 def _generate_environment(input_env, parent_env=None):
68 if parent_env is None:
70 env = dict(parent_env)
71 env.pop('children', None)
73 parameter_defaults = {}
75 sample_values = env.get('sample_values', {})
76 static_names = env.get('static', [])
77 for template_file, template_data in env['files'].items():
78 with open(template_file) as f:
79 f_data = yaml.safe_load(f)
80 f_params = f_data['parameters']
81 parameter_defaults.update(f_params)
82 if template_data['parameters'] == 'all':
83 new_names = [k for k, v in f_params.items()]
84 for hidden in _HIDDEN_PARAMS:
85 if (hidden not in (static_names + sample_values.keys()) and
87 new_names.remove(hidden)
89 new_names = template_data['parameters']
90 missing_params = [name for name in new_names
91 if name not in f_params]
93 raise RuntimeError('Did not find specified parameter names %s '
94 'in file %s for environment %s' %
95 (missing_params, template_file,
97 param_names += new_names
99 static_defaults = {k: v for k, v in parameter_defaults.items()
100 if k in param_names and
103 parameter_defaults = {k: v for k, v in parameter_defaults.items()
104 if k in param_names and
105 k not in _PRIVATE_OVERRIDES and
106 not k.startswith('_') and
107 k not in static_names
110 for k, v in sample_values.items():
111 if k in parameter_defaults:
112 parameter_defaults[k]['sample'] = v
113 if k in static_defaults:
114 static_defaults[k]['sample'] = v
116 def write_sample_entry(f, name, value):
117 default = value.get('default')
120 mandatory = ('# Mandatory. This parameter must be set by the '
123 if value.get('sample') is not None:
124 default = value['sample']
125 # We ultimately cast this to str for output anyway
126 default = str(default)
129 # If the default value is something like %index%, yaml won't
130 # parse the output correctly unless we wrap it in quotes.
131 # However, not all default values can be wrapped so we need to
132 # do it conditionally.
133 if default.startswith('%'):
134 default = "'%s'" % default
135 if not default.startswith('\n'):
136 default = ' ' + default
138 values = {'name': name,
139 'type': value['type'],
141 value.get('description', '').rstrip().replace('\n',
144 'mandatory': mandatory,
146 f.write(_PARAM_FORMAT % values + '\n')
148 target_file = os.path.join('environments', env['name'] + '.yaml')
149 _create_output_dir(target_file)
150 with open(target_file, 'w') as env_file:
151 env_file.write(_FILE_HEADER)
152 # TODO(bnemec): Once Heat allows the title and description to live in
153 # the environment itself, uncomment these entries and make them
154 # top-level keys in the YAML.
155 env_title = env.get('title', '')
156 env_file.write(u'# title: %s\n' % env_title)
157 env_desc = env.get('description', '')
158 env_file.write(u'# description: |\n')
159 for line in env_desc.splitlines():
160 env_file.write(u'# %s\n' % line)
162 if parameter_defaults:
163 env_file.write(u'parameter_defaults:\n')
164 for name, value in sorted(parameter_defaults.items()):
165 write_sample_entry(env_file, name, value)
167 env_file.write(_STATIC_MESSAGE_START)
168 for name, value in sorted(static_defaults.items()):
169 write_sample_entry(env_file, name, value)
171 env_file.write(_STATIC_MESSAGE_END)
173 if env.get('resource_registry'):
174 env_file.write(u'resource_registry:\n')
175 for res, value in sorted(env.get('resource_registry', {}).items()):
176 env_file.write(u' %s: %s\n' % (res, value))
177 print('Wrote sample environment "%s"' % target_file)
179 for e in env.get('children', []):
180 _generate_environment(e, env)
183 def generate_environments(config_path):
184 if os.path.isdir(config_path):
185 config_files = os.listdir(config_path)
186 config_files = [os.path.join(config_path, i) for i in config_files
187 if os.path.splitext(i)[1] == '.yaml']
189 config_files = [config_path]
190 for config_file in config_files:
191 print('Reading environment definitions from %s' % config_file)
192 with open(config_file) as f:
193 config = yaml.safe_load(f)
194 for env in config['environments']:
195 _generate_environment(env)
198 def usage(exit_code=1):
199 print('Usage: %s [<filename.yaml> | <directory>]' % sys.argv[0])
205 config_path = sys.argv[1]
208 generate_environments(config_path)
211 if __name__ == '__main__':