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
25 from toscaparser.tosca_template import ToscaTemplate
26 from toscaparser.utils.gettextutils import _
27 from toscaparser.utils.urlutils import UrlUtils
28 from translator.common import utils
29 from translator.hot.tosca_translator import TOSCATranslator
32 Test the heat-translator translation from command line as:
34 --template-file=<path to the YAML template>
35 --template-type=<type of template e.g. tosca>
36 --parameters="purpose=test"
37 Takes three user arguments,
38 1. type of translation (e.g. tosca) (required)
39 2. Path to the file that needs to be translated (required)
40 3. Input parameters (optional)
42 In order to use heat-translator to only validate template,
43 without actual translation, pass --validate-only=true along with
44 other required arguments.
48 logging.config.fileConfig('heat_translator_logging.conf')
49 log = logging.getLogger("heat-translator")
52 class TranslatorShell(object):
54 SUPPORTED_TYPES = ['tosca']
56 def _validate(self, args):
58 msg = _("The program requires minimum two arguments. "
59 "Please refer to the usage documentation.")
62 if "--template-file=" not in args[0]:
63 msg = _("The program expects --template-file as first argument. "
64 "Please refer to the usage documentation.")
67 if "--template-type=" not in args[1]:
68 msg = _("The program expects --template-type as second argument. "
69 "Please refer to the usage documentation.")
74 # TODO(spzala): set self.deploy based on passed args once support for
75 # --deploy argument is enabled.
78 path = args[0].split('--template-file=')[1]
79 # e.g. --template_file=translator/tests/data/tosca_helloworld.yaml
80 template_type = args[1].split('--template-type=')[1]
81 # e.g. --template_type=tosca
83 msg = _("Template type is needed. For example, 'tosca'")
86 elif template_type not in self.SUPPORTED_TYPES:
87 msg = _("%(value)s is not a valid template type.") % {
88 'value': template_type}
97 if "--validate-only=" in arg:
99 if "--parameters=" in arg:
101 if "--output-file=" in arg:
103 output_file = output.split('--output-file=')[1]
104 if "--deploy" in arg:
107 parsed_params = self._parse_parameters(parameters)
108 a_file = os.path.isfile(path)
109 a_url = UrlUtils.validate_url(path) if not a_file else False
111 run_only_validation = False
113 value = validate_only.split('-validate-only=')[1].lower()
114 if template_type == 'tosca' and value == 'true':
115 run_only_validation = True
116 if run_only_validation:
117 ToscaTemplate(path, parsed_params, a_file)
118 msg = (_('The input "%(path)s" successfully passed '
119 'validation.') % {'path': path})
123 _('Checked whether template path is a file or url path.'))
124 heat_tpl = self._translate(template_type, path, parsed_params,
127 if utils.check_for_env_variables() and self.deploy:
129 heatclient(heat_tpl, parsed_params)
131 log.error(_("Unable to launch the heat stack"))
133 self._write_output(heat_tpl, output_file)
135 msg = _("The path %(path)s is not a valid file or URL.") % {
138 raise ValueError(msg)
140 def _parse_parameters(self, parameter_list):
142 if parameter_list.startswith('--parameters'):
143 # Parameters are semi-colon separated
144 inputs = parameter_list.split('--parameters=')[1].\
145 replace('"', '').split(';')
146 # Each parameter should be an assignment
148 keyvalue = param.split('=')
149 # Validate the parameter has both a name and value
150 msg = _("'%(param)s' is not a well-formed parameter.") % {
152 if keyvalue.__len__() is 2:
153 # Assure parameter name is not zero-length or whitespace
154 stripped_name = keyvalue[0].strip()
155 if not stripped_name:
157 raise ValueError(msg)
158 # Add the valid parameter to the dictionary
159 parsed_inputs[keyvalue[0]] = keyvalue[1]
162 raise ValueError(msg)
164 msg = _("'%(list)s' is not a valid parameter list.") % {
165 'list': parameter_list}
167 raise ValueError(msg)
170 def _translate(self, sourcetype, path, parsed_params, a_file):
172 if sourcetype == "tosca":
173 log.debug(_('Loading the tosca template.'))
174 tosca = ToscaTemplate(path, parsed_params, a_file)
175 translator = TOSCATranslator(tosca, parsed_params, self.deploy)
176 log.debug(_('Translating the tosca template.'))
177 output = translator.translate()
180 def _write_output(self, output, output_file=None):
183 with open(output_file, 'w+') as f:
189 def heatclient(output, params):
191 access_dict = utils.get_ks_access_dict()
192 endpoint = utils.get_url_for(access_dict, 'orchestration')
193 token = utils.get_token_id(access_dict)
194 except Exception as e:
197 'Content-Type': 'application/json',
198 'X-Auth-Token': token
200 heat_stack_name = "heat_" + str(uuid.uuid4()).split("-")[0]
201 output = yaml.load(output)
202 output['heat_template_version'] = str(output['heat_template_version'])
204 'stack_name': heat_stack_name,
208 response = requests.post(endpoint + '/stacks',
209 data=json.dumps(data),
211 content = ast.literal_eval(response._content)
212 if response.status_code == 201:
213 stack_id = content["stack"]["id"]
214 get_url = endpoint + '/stacks/' + heat_stack_name + '/' + stack_id
215 get_stack_response = requests.get(get_url,
217 stack_details = json.loads(get_stack_response.content)["stack"]
218 col_names = ["id", "stack_name", "stack_status", "creation_time",
220 pt = prettytable.PrettyTable(col_names)
222 for col in col_names:
223 stack_list.append(stack_details[col])
224 pt.add_row(stack_list)
227 err_msg = content["error"]["message"]
228 log(_("Unable to deploy to Heat\n%s\n") % err_msg)
234 TranslatorShell().main(args)
237 if __name__ == '__main__':