1 # Licensed under the Apache License, Version 2.0 (the "License"); you may
2 # not use this file except in compliance with the License. You may obtain
3 # a copy of the License at
5 # http://www.apache.org/licenses/LICENSE-2.0
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 # License for the specific language governing permissions and limitations
26 from toscaparser.tosca_template import ToscaTemplate
27 from toscaparser.utils.gettextutils import _
28 from toscaparser.utils.urlutils import UrlUtils
29 from translator.common import utils
30 from translator.conf.config import ConfigProvider
31 from translator.hot.tosca_translator import TOSCATranslator
34 Test the heat-translator translation from command line as:
36 --template-file=<path to the YAML template>
37 --template-type=<type of template e.g. tosca>
38 --parameters="purpose=test"
39 Takes three user arguments,
40 1. type of translation (e.g. tosca) (required)
41 2. Path to the file that needs to be translated (required)
42 3. Input parameters (optional)
44 In order to use heat-translator to only validate template,
45 without actual translation, pass --validate-only=true along with
46 other required arguments.
49 conf_file = ConfigProvider.get_translator_logging_file()
50 logging.config.fileConfig(conf_file)
51 log = logging.getLogger("heat-translator")
54 class TranslatorShell(object):
56 SUPPORTED_TYPES = ['tosca']
59 parser = argparse.ArgumentParser(prog="heat-translator")
61 parser.add_argument('--template-file',
64 help=_('Template file to load.'))
66 parser.add_argument('--output-file',
68 help=_('Where to store the output file. If not '
69 'passed, it will be printed to stdin.'))
71 parser.add_argument('--template-type',
72 metavar='<input-template-type>',
73 choices=self.SUPPORTED_TYPES,
75 help=(_('Template type to parse. Choose between '
76 '%s.') % self.SUPPORTED_TYPES))
78 parser.add_argument('--parameters',
79 metavar='<param1=val1;param2=val2;...>',
80 help=_('Optional input parameters.'))
82 parser.add_argument('--validate-only',
85 help=_('Only validate input template, do not '
86 'perform translation.'))
88 parser.add_argument('--deploy',
91 help=_('Whether to deploy the generated template '
94 parser.add_argument('--stack-name',
95 metavar='<stack-name>',
97 help=_('Stack name when deploy the generated '
102 def main(self, argv):
104 parser = self.get_parser()
105 (args, args_list) = parser.parse_known_args(argv)
107 template_file = args.template_file
108 template_type = args.template_type
109 output_file = args.output_file
110 validate_only = args.validate_only
112 stack_name = args.stack_name
116 parsed_params = self._parse_parameters(args.parameters)
118 a_file = os.path.isfile(template_file)
119 a_url = UrlUtils.validate_url(template_file) if not a_file else False
122 ToscaTemplate(template_file, parsed_params, a_file)
123 msg = (_('The input "%(template_file)s" successfully passed '
124 'validation.') % {'template_file': template_file})
127 heat_tpl = self._translate(template_type, template_file,
128 parsed_params, a_file, deploy)
130 if utils.check_for_env_variables() and deploy:
132 file_name = os.path.basename(
133 os.path.splitext(template_file)[0])
134 heatclient(heat_tpl, stack_name,
135 file_name, parsed_params)
137 log.error(_("Unable to launch the heat stack"))
139 self._write_output(heat_tpl, output_file)
141 msg = (_('The path %(template_file)s is not a valid '
142 'file or URL.') % {'template_file': template_file})
145 raise ValueError(msg)
147 def _parse_parameters(self, parameter_list):
150 # Parameters are semi-colon separated
151 inputs = parameter_list.replace('"', '').split(';')
152 # Each parameter should be an assignment
154 keyvalue = param.split('=')
155 # Validate the parameter has both a name and value
156 msg = _("'%(param)s' is not a well-formed parameter.") % {
158 if keyvalue.__len__() is 2:
159 # Assure parameter name is not zero-length or whitespace
160 stripped_name = keyvalue[0].strip()
161 if not stripped_name:
163 raise ValueError(msg)
164 # Add the valid parameter to the dictionary
165 parsed_inputs[keyvalue[0]] = keyvalue[1]
168 raise ValueError(msg)
171 def _translate(self, sourcetype, path, parsed_params, a_file, deploy):
173 if sourcetype == "tosca":
174 log.debug(_('Loading the tosca template.'))
175 tosca = ToscaTemplate(path, parsed_params, a_file)
176 translator = TOSCATranslator(tosca, parsed_params, deploy)
177 log.debug(_('Translating the tosca template.'))
178 output = translator.translate()
181 def _write_output(self, output, output_file=None):
184 with open(output_file, 'w+') as f:
190 def heatclient(output, stack_name, file_name, params):
192 access_dict = utils.get_ks_access_dict()
193 endpoint = utils.get_url_for(access_dict, 'orchestration')
194 token = utils.get_token_id(access_dict)
195 except Exception as e:
198 'Content-Type': 'application/json',
199 'X-Auth-Token': token
202 heat_stack_name = stack_name if stack_name else \
203 "heat_" + file_name + '_' + str(uuid.uuid4()).split("-")[0]
204 output = yaml.load(output)
205 output['heat_template_version'] = str(output['heat_template_version'])
207 'stack_name': heat_stack_name,
211 response = requests.post(endpoint + '/stacks',
212 data=json.dumps(data),
214 content = ast.literal_eval(response._content)
215 if response.status_code == 201:
216 stack_id = content["stack"]["id"]
217 get_url = endpoint + '/stacks/' + heat_stack_name + '/' + stack_id
218 get_stack_response = requests.get(get_url,
220 stack_details = json.loads(get_stack_response.content)["stack"]
221 col_names = ["id", "stack_name", "stack_status", "creation_time",
223 pt = prettytable.PrettyTable(col_names)
225 for col in col_names:
226 stack_list.append(stack_details[col])
227 pt.add_row(stack_list)
230 err_msg = content["error"]["message"]
231 log(_("Unable to deploy to Heat\n%s\n") % err_msg)
237 TranslatorShell().main(args)
240 if __name__ == '__main__':