Delete not used property from vRNC
[parser.git] / tosca2heat / heat-translator / translator / shell.py
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
4 #
5 #         http://www.apache.org/licenses/LICENSE-2.0
6 #
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
11 #    under the License.
12
13
14 import argparse
15 import ast
16 import json
17 import logging
18 import logging.config
19 import os
20 import prettytable
21 import requests
22 import sys
23 import uuid
24 import yaml
25
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
32
33 """
34 Test the heat-translator translation from command line as:
35 #heat-translator
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)
43
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.
47
48 """
49 conf_file = ConfigProvider.get_translator_logging_file()
50 logging.config.fileConfig(conf_file)
51 log = logging.getLogger("heat-translator")
52
53
54 class TranslatorShell(object):
55
56     SUPPORTED_TYPES = ['tosca']
57
58     def get_parser(self):
59         parser = argparse.ArgumentParser(prog="heat-translator")
60
61         parser.add_argument('--template-file',
62                             metavar='<filename>',
63                             required=True,
64                             help=_('Template file to load.'))
65
66         parser.add_argument('--output-file',
67                             metavar='<filename>',
68                             help=_('Where to store the output file. If not '
69                                    'passed, it will be printed to stdin.'))
70
71         parser.add_argument('--template-type',
72                             metavar='<input-template-type>',
73                             choices=self.SUPPORTED_TYPES,
74                             default='tosca',
75                             help=(_('Template type to parse. Choose between '
76                                     '%s.') % self.SUPPORTED_TYPES))
77
78         parser.add_argument('--parameters',
79                             metavar='<param1=val1;param2=val2;...>',
80                             help=_('Optional input parameters.'))
81
82         parser.add_argument('--validate-only',
83                             action='store_true',
84                             default=False,
85                             help=_('Only validate input template, do not '
86                                    'perform translation.'))
87
88         parser.add_argument('--deploy',
89                             action='store_true',
90                             default=False,
91                             help=_('Whether to deploy the generated template '
92                                    'or not.'))
93
94         parser.add_argument('--stack-name',
95                             metavar='<stack-name>',
96                             required=False,
97                             help=_('Stack name when deploy the generated '
98                                    'template.'))
99
100         return parser
101
102     def main(self, argv):
103
104         parser = self.get_parser()
105         (args, args_list) = parser.parse_known_args(argv)
106
107         template_file = args.template_file
108         template_type = args.template_type
109         output_file = args.output_file
110         validate_only = args.validate_only
111         deploy = args.deploy
112         stack_name = args.stack_name
113
114         parsed_params = {}
115         if args.parameters:
116             parsed_params = self._parse_parameters(args.parameters)
117
118         a_file = os.path.isfile(template_file)
119         a_url = UrlUtils.validate_url(template_file) if not a_file else False
120         if a_file or a_url:
121             if validate_only:
122                 ToscaTemplate(template_file, parsed_params, a_file)
123                 msg = (_('The input "%(template_file)s" successfully passed '
124                          'validation.') % {'template_file': template_file})
125                 print(msg)
126             else:
127                 heat_tpl = self._translate(template_type, template_file,
128                                            parsed_params, a_file, deploy)
129                 if heat_tpl:
130                     if utils.check_for_env_variables() and deploy:
131                         try:
132                             file_name = os.path.basename(
133                                 os.path.splitext(template_file)[0])
134                             heatclient(heat_tpl, stack_name,
135                                        file_name, parsed_params)
136                         except Exception:
137                             log.error(_("Unable to launch the heat stack"))
138
139                     self._write_output(heat_tpl, output_file)
140         else:
141             msg = (_('The path %(template_file)s is not a valid '
142                      'file or URL.') % {'template_file': template_file})
143
144             log.error(msg)
145             raise ValueError(msg)
146
147     def _parse_parameters(self, parameter_list):
148         parsed_inputs = {}
149
150         # Parameters are semi-colon separated
151         inputs = parameter_list.replace('"', '').split(';')
152         # Each parameter should be an assignment
153         for param in inputs:
154             keyvalue = param.split('=')
155             # Validate the parameter has both a name and value
156             msg = _("'%(param)s' is not a well-formed parameter.") % {
157                 'param': param}
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:
162                     log.error(msg)
163                     raise ValueError(msg)
164                 # Add the valid parameter to the dictionary
165                 parsed_inputs[keyvalue[0]] = keyvalue[1]
166             else:
167                 log.error(msg)
168                 raise ValueError(msg)
169         return parsed_inputs
170
171     def _translate(self, sourcetype, path, parsed_params, a_file, deploy):
172         output = None
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()
179         return output
180
181     def _write_output(self, output, output_file=None):
182         if output:
183             if output_file:
184                 with open(output_file, 'w+') as f:
185                     f.write(output)
186             else:
187                 print(output)
188
189
190 def heatclient(output, stack_name, file_name, params):
191     try:
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:
196         log.error(e)
197     headers = {
198         'Content-Type': 'application/json',
199         'X-Auth-Token': token
200     }
201
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'])
206     data = {
207         'stack_name': heat_stack_name,
208         'template': output,
209         'parameters': params
210     }
211     response = requests.post(endpoint + '/stacks',
212                              data=json.dumps(data),
213                              headers=headers)
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,
219                                           headers=headers)
220         stack_details = json.loads(get_stack_response.content)["stack"]
221         col_names = ["id", "stack_name", "stack_status", "creation_time",
222                      "updated_time"]
223         pt = prettytable.PrettyTable(col_names)
224         stack_list = []
225         for col in col_names:
226             stack_list.append(stack_details[col])
227         pt.add_row(stack_list)
228         print(pt)
229     else:
230         err_msg = content["error"]["message"]
231         log(_("Unable to deploy to Heat\n%s\n") % err_msg)
232
233
234 def main(args=None):
235     if args is None:
236         args = sys.argv[1:]
237     TranslatorShell().main(args)
238
239
240 if __name__ == '__main__':
241     main()