v0.4.47 cloud-init for ssh key injection at instance-scenario-create
[osm/RO.git] / openmano
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # PYTHON_ARGCOMPLETE_OK
4
5 ##
6 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
7 # This file is part of openmano
8 # All Rights Reserved.
9 #
10 # Licensed under the Apache License, Version 2.0 (the "License"); you may
11 # not use this file except in compliance with the License. You may obtain
12 # a copy of the License at
13 #
14 #         http://www.apache.org/licenses/LICENSE-2.0
15 #
16 # Unless required by applicable law or agreed to in writing, software
17 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
18 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
19 # License for the specific language governing permissions and limitations
20 # under the License.
21 #
22 # For those usages not covered by the Apache License, Version 2.0 please
23 # contact with: nfvlabs@tid.es
24 ##
25
26 '''
27 openmano client used to interact with openmano-server (openmanod) 
28 '''
29 __author__="Alfonso Tierno, Gerardo Garcia"
30 __date__ ="$09-oct-2014 09:09:48$"
31 __version__="0.4.5-r489"
32 version_date="Aug 2016"
33
34 from argcomplete.completers import FilesCompleter
35 import os
36 import argparse
37 import argcomplete
38 import requests
39 import json
40 import yaml
41 import logging
42 #from jsonschema import validate as js_v, exceptions as js_e
43
44 class ArgumentParserError(Exception): pass
45
46 class OpenmanoCLIError(Exception): pass
47
48 class ThrowingArgumentParser(argparse.ArgumentParser):
49     def error(self, message):
50         print "Error: %s" %message
51         print
52         self.print_usage()
53         #self.print_help()
54         print
55         print "Type 'openmano -h' for help"
56         raise ArgumentParserError
57
58
59 def config(args):
60     print "OPENMANO_HOST: %s" %mano_host
61     print "OPENMANO_PORT: %s" %mano_port
62     if args.n:
63         logger.debug("resolving tenant and datacenter names")
64         mano_tenant_id = "None"
65         mano_tenant_name = "None"
66         mano_datacenter_id = "None"
67         mano_datacenter_name = "None"
68         try:
69             mano_tenant_id = _get_item_uuid("tenants", mano_tenant)
70             URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, mano_tenant_id)
71             mano_response = requests.get(URLrequest)
72             logger.debug("openmano response: %s", mano_response.text )
73             content = mano_response.json()
74             mano_tenant_name = content["tenant"]["name"]
75             URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, mano_tenant_id, mano_datacenter)
76             mano_response = requests.get(URLrequest)
77             logger.debug("openmano response: %s", mano_response.text )
78             content = mano_response.json()
79             if "error" not in content:
80                 mano_datacenter_id = content["datacenter"]["uuid"]
81                 mano_datacenter_name = content["datacenter"]["name"]
82         except OpenmanoCLIError:
83             pass
84         print "OPENMANO_TENANT: %s" %mano_tenant
85         print "    Id: %s" %mano_tenant_id
86         print "    Name: %s" %mano_tenant_name 
87         print "OPENMANO_DATACENTER: %s" %str (mano_datacenter)
88         print "    Id: %s" %mano_datacenter_id
89         print "    Name: %s" %mano_datacenter_name 
90     else:
91         print "OPENMANO_TENANT: %s" %mano_tenant
92         print "OPENMANO_DATACENTER: %s" %str (mano_datacenter)
93
94 def _print_verbose(mano_response, verbose_level=0):
95     content = mano_response.json()
96     result = 0 if mano_response.status_code==200 else mano_response.status_code
97     if type(content)!=dict or len(content)!=1:
98         #print "Non expected format output"
99         print str(content)
100         return result
101     
102     val=content.values()[0]
103     if type(val)==str:
104         print val
105         return result
106     elif type(val) == list:
107         content_list = val
108     elif type(val)==dict:
109         content_list = [val]
110     else:
111         #print "Non expected dict/list format output"
112         print str(content)
113         return result
114     
115     #print content_list
116     if verbose_level==None:
117         verbose_level=0
118     if verbose_level >= 3:
119         print yaml.safe_dump(content, indent=4, default_flow_style=False)
120         return result
121
122     if mano_response.status_code == 200:
123         for content in content_list:
124             if "uuid" in content:
125                 uuid = content['uuid']
126             elif "id" in content:
127                 uuid = content['id']
128             elif "vim_id" in content:
129                 uuid = content['vim_id']
130             myoutput = "%s %s" %(uuid.ljust(38),content['name'].ljust(20))
131             if "status" in content:
132                 myoutput += " " + content['status'].ljust(20)
133             elif "enabled" in content and not content["enabled"]:
134                 myoutput += " enabled=False".ljust(20)
135             if verbose_level >=1:
136                 if 'created_at' in content:
137                     myoutput += " " + content['created_at'].ljust(20)
138                 if verbose_level >=2:
139                     new_line='\n'
140                     if 'type' in content and content['type']!=None:
141                         myoutput += new_line + "  Type: " + content['type'].ljust(29)
142                         new_line=''
143                     if 'description' in content and content['description']!=None:
144                         myoutput += new_line + "  Description: " + content['description'].ljust(20)
145             print myoutput
146     else:
147         print content['error']['description']
148     return result
149
150 def parser_json_yaml(file_name):
151     try:
152         f = file(file_name, "r")
153         text = f.read()
154         f.close()
155     except Exception as e:
156         return (False, str(e))
157            
158     #Read and parse file
159     if file_name[-5:]=='.yaml' or file_name[-4:]=='.yml' or (file_name[-5:]!='.json' and '\t' not in text):
160         try:
161             config = yaml.load(text)
162         except yaml.YAMLError as exc:
163             error_pos = ""
164             if hasattr(exc, 'problem_mark'):
165                 mark = exc.problem_mark
166                 error_pos = " at line:%s column:%s" % (mark.line+1, mark.column+1)
167             return (False, "Error loading file '"+file_name+"' yaml format error" + error_pos)
168     else: #json
169         try:
170             config = json.loads(text) 
171         except Exception as e:
172             return (False, "Error loading file '"+file_name+"' json format error " + str(e) )
173
174     return True, config
175
176 def _load_file_or_yaml(content):
177     '''
178     'content' can be or a yaml/json file or a text containing a yaml/json text format
179     This function autodetect, trying to load and parse the file,
180     if fails trying to parse the 'content' text
181     Returns the dictionary once parsed, or print an error and finish the program
182     '''
183     #Check config file exists
184     if os.path.isfile(content):
185         r,payload = parser_json_yaml(content)
186         if not r:
187             print payload
188             exit(-1)
189     elif "{" in content or ":" in content:
190         try:
191             payload = yaml.load(content)
192         except yaml.YAMLError as exc:
193             error_pos = ""
194             if hasattr(exc, 'problem_mark'):
195                 mark = exc.problem_mark
196                 error_pos = " at position: (%s:%s)" % (mark.line+1, mark.column+1)
197             print "Error loading yaml/json text"+error_pos
198             exit (-1)
199     else:
200         print "'%s' is neither a valid file nor a yaml/json content" % content
201         exit(-1)
202     return payload
203
204 def _get_item_uuid(item, item_name_id, tenant=None):
205     if tenant:
206         URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, tenant, item)
207     else:
208         URLrequest = "http://%s:%s/openmano/%s" %(mano_host, mano_port, item)
209     mano_response = requests.get(URLrequest)
210     logger.debug("openmano response: %s", mano_response.text )
211     content = mano_response.json()
212     #print content
213     found = 0
214     for i in content[item]:
215         if i["uuid"] == item_name_id:
216             return item_name_id
217         if i["name"] == item_name_id:
218             uuid = i["uuid"]
219             found += 1
220     if found == 0:
221         raise OpenmanoCLIError("No %s found with name/uuid '%s'" %(item[:-1], item_name_id))
222     elif found > 1:
223         raise OpenmanoCLIError("%d %s found with name '%s'. uuid must be used" %(found, item, item_name_id))
224     return uuid
225
226 # def check_valid_uuid(uuid):
227 #     id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
228 #     try:
229 #         js_v(uuid, id_schema)
230 #         return True
231 #     except js_e.ValidationError:
232 #         return False
233     
234 def _get_tenant(tenant_name_id = None):
235     if not tenant_name_id:
236         tenant_name_id = mano_tenant
237         if not mano_tenant:
238             raise OpenmanoCLIError("'OPENMANO_TENANT' environment variable is not set")
239     return _get_item_uuid("tenants", tenant_name_id)
240
241 def _get_datacenter(datacenter_name_id = None, tenant = "any"):
242     if not datacenter_name_id:
243         datacenter_name_id = mano_datacenter
244         if not datacenter_name_id:
245             raise OpenmanoCLIError("neither 'OPENMANO_DATACENTER' environment variable is set nor --datacenter option is used")
246     return _get_item_uuid("datacenters", datacenter_name_id, tenant)
247
248 def vnf_create(args):
249     #print "vnf-create",args
250     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
251     tenant = _get_tenant()
252     myvnf = _load_file_or_yaml(args.file)
253
254     if args.name or args.description or args.image_path:
255         #print args.name
256         try:
257             if args.name:
258                 myvnf['vnf']['name'] = args.name
259             if args.description:
260                 myvnf['vnf']['description'] = args.description
261             if args.image_path:
262                 index=0
263                 for image_path_ in args.image_path.split(","):
264                     #print "image-path", image_path_
265                     myvnf['vnf']['VNFC'][index]['VNFC image']=image_path_
266                     index=index+1
267         except (KeyError, TypeError), e:
268             if str(e)=='vnf':           error_pos= "missing field 'vnf'"
269             elif str(e)=='name':        error_pos= "missing field  'vnf':'name'"
270             elif str(e)=='description': error_pos= "missing field  'vnf':'description'"
271             elif str(e)=='VNFC':        error_pos= "missing field  'vnf':'VNFC'"
272             elif str(e)==str(index):    error_pos= "field  'vnf':'VNFC' must be an array"
273             elif str(e)=='VNFC image':  error_pos= "missing field 'vnf':'VNFC'['VNFC image']"
274             else:                       error_pos="wrong format"
275             print "Wrong VNF descriptor: " + error_pos
276             return -1 
277     payload_req = json.dumps(myvnf)
278         
279     #print payload_req
280         
281     URLrequest = "http://%s:%s/openmano/%s/vnfs" %(mano_host, mano_port, tenant)
282     logger.debug("openmano request: %s", payload_req)
283     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
284     logger.debug("openmano response: %s", mano_response.text )
285
286     return _print_verbose(mano_response, args.verbose)
287
288 def vnf_list(args):
289     #print "vnf-list",args
290     if args.all:
291         tenant = "any"
292     else:
293         tenant = _get_tenant()
294     if args.name:
295         toshow = _get_item_uuid("vnfs", args.name, tenant)
296         URLrequest = "http://%s:%s/openmano/%s/vnfs/%s" %(mano_host, mano_port, tenant, toshow)
297     else:
298         URLrequest = "http://%s:%s/openmano/%s/vnfs" %(mano_host, mano_port, tenant)
299     mano_response = requests.get(URLrequest)
300     logger.debug("openmano response: %s", mano_response.text )
301     content = mano_response.json()
302     #print json.dumps(content, indent=4)
303     if args.verbose==None:
304         args.verbose=0
305     result = 0 if mano_response.status_code==200 else mano_response.status_code
306     if mano_response.status_code == 200:
307         if not args.name:
308             if args.verbose >= 3:
309                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
310                 return result
311             if len(content['vnfs']) == 0:
312                 print "No VNFs were found."
313                 return 404 #HTTP_Not_Found
314             for vnf in content['vnfs']:
315                 myoutput = "%s %s" %(vnf['uuid'].ljust(38),vnf['name'].ljust(20))
316                 if args.verbose >=1:
317                     myoutput = "%s %s" %(myoutput, vnf['created_at'].ljust(20))
318                 print myoutput
319                 if args.verbose >=2:
320                     print "  Description: %s" %vnf['description']
321                     print "  VNF descriptor file: %s" %vnf['path']
322         else:
323             if args.verbose:
324                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
325                 return result
326             vnf = content['vnf']
327             print "%s %s %s" %(vnf['uuid'].ljust(38),vnf['name'].ljust(20), vnf['created_at'].ljust(20))
328             print "  Description: %s" %vnf['description']
329             #print "  VNF descriptor file: %s" %vnf['path']
330             print "    VMs:"
331             for vm in vnf['VNFC']:
332                 #print "    %s %s %s" %(vm['name'].ljust(20), vm['uuid'].ljust(38), vm['description'].ljust(30))
333                 print "        %s %s" %(vm['name'].ljust(20), vm['description'])
334             if len(vnf['nets'])>0:
335                 print "    Internal nets:"
336                 for net in vnf['nets']:
337                     print "        %s %s" %(net['name'].ljust(20), net['description'])
338             if len(vnf['external-connections'])>0:
339                 print "    External interfaces:"
340                 for interface in vnf['external-connections']:
341                     print "        %s %s %s %s" %(interface['external_name'].ljust(20), interface['vm_name'].ljust(20), interface['internal_name'].ljust(20), \
342                                                   interface['vpci'].ljust(14))
343     else:
344         print content['error']['description']
345         if args.verbose:
346             print yaml.safe_dump(content, indent=4, default_flow_style=False)
347     return result
348
349 def vnf_delete(args):
350     #print "vnf-delete",args
351     if args.all:
352         tenant = "any"
353     else:
354         tenant = _get_tenant()
355     todelete = _get_item_uuid("vnfs", args.name, tenant=tenant)
356     if not args.force:
357         r = raw_input("Delete VNF %s (y/N)? " %(todelete))
358         if  not (len(r)>0  and r[0].lower()=="y"):
359             return 0
360     URLrequest = "http://%s:%s/openmano/%s/vnfs/%s" %(mano_host, mano_port, tenant, todelete)
361     mano_response = requests.delete(URLrequest)
362     logger.debug("openmano response: %s", mano_response.text )
363     result = 0 if mano_response.status_code==200 else mano_response.status_code
364     content = mano_response.json()
365     #print json.dumps(content, indent=4)
366     if mano_response.status_code == 200:
367         print content['result']
368     else:
369         print content['error']['description']
370     return result
371
372 def scenario_create(args):
373     #print "scenario-create",args
374     tenant = _get_tenant()
375     headers_req = {'content-type': 'application/yaml'}
376     myscenario = _load_file_or_yaml(args.file)
377
378     if args.name:
379         myscenario['name'] = args.name
380     if args.description:
381         myscenario['description'] = args.description
382     payload_req = yaml.safe_dump(myscenario, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
383     
384     #print payload_req
385         
386     URLrequest = "http://%s:%s/openmano/%s/scenarios" %(mano_host, mano_port, tenant)
387     logger.debug("openmano request: %s", payload_req)
388     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
389     logger.debug("openmano response: %s", mano_response.text )
390     return _print_verbose(mano_response, args.verbose)
391
392 def scenario_list(args):
393     #print "scenario-list",args
394     if args.all:
395         tenant = "any"
396     else:
397         tenant = _get_tenant()
398     if args.name:
399         toshow = _get_item_uuid("scenarios", args.name, tenant)
400         URLrequest = "http://%s:%s/openmano/%s/scenarios/%s" %(mano_host, mano_port, tenant, toshow)
401     else:
402         URLrequest = "http://%s:%s/openmano/%s/scenarios" %(mano_host, mano_port, tenant)
403     mano_response = requests.get(URLrequest)
404     logger.debug("openmano response: %s", mano_response.text )
405     content = mano_response.json()
406     #print json.dumps(content, indent=4)
407     if args.verbose==None:
408         args.verbose=0
409
410     result = 0 if mano_response.status_code==200 else mano_response.status_code
411     if mano_response.status_code == 200:
412         if not args.name:
413             if args.verbose >= 3:
414                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
415                 return result
416             if len(content['scenarios']) == 0:
417                 print "No scenarios were found."
418                 return 404 #HTTP_Not_Found
419             for scenario in content['scenarios']:
420                 myoutput = "%s %s" %(scenario['uuid'].ljust(38),scenario['name'].ljust(20))
421                 if args.verbose >=1:
422                     myoutput = "%s %s" %(myoutput, scenario['created_at'].ljust(20))
423                 print myoutput
424                 if args.verbose >=2:
425                     print "  Description: %s" %scenario['description']
426         else:
427             if args.verbose:
428                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
429                 return result
430             scenario = content['scenario']
431             myoutput = "%s %s %s" %(scenario['uuid'].ljust(38),scenario['name'].ljust(20), scenario['created_at'].ljust(20))
432             print myoutput
433             print "  Description: %s" %scenario['description']
434             print "    VNFs:"
435             for vnf in scenario['vnfs']:
436                 print "        %s %s %s" %(vnf['name'].ljust(20), vnf['vnf_id'].ljust(38), vnf['description'])
437             if len(scenario['nets'])>0:
438                 print "    Internal nets:"
439                 for net in scenario['nets']:
440                     if net['description'] is None:   #if description does not exist, description is "-". Valid for external and internal nets.
441                         net['description'] = '-' 
442                     if not net['external']:
443                         print "        %s %s %s" %(net['name'].ljust(20), net['uuid'].ljust(38), net['description'].ljust(30))
444                 print "    External nets:"
445                 for net in scenario['nets']:
446                     if net['external']:
447                         print "        %s %s %s vim-id:%s" %(net['name'].ljust(20), net['uuid'].ljust(38), net['description'].ljust(30), net['vim_id'])
448     else:
449         print content['error']['description']
450         if args.verbose:
451             print yaml.safe_dump(content, indent=4, default_flow_style=False)
452     return result
453
454 def scenario_delete(args):
455     #print "scenario-delete",args
456     if args.all:
457         tenant = "any"
458     else:
459         tenant = _get_tenant()
460     todelete = _get_item_uuid("scenarios", args.name, tenant=tenant)
461     if not args.force:
462         r = raw_input("Delete scenario %s (y/N)? " %(args.name))
463         if  not (len(r)>0  and r[0].lower()=="y"):
464             return 0
465     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s" %(mano_host, mano_port, tenant, todelete)
466     mano_response = requests.delete(URLrequest)
467     logger.debug("openmano response: %s", mano_response.text )
468     result = 0 if mano_response.status_code==200 else mano_response.status_code
469     content = mano_response.json()
470     #print json.dumps(content, indent=4)
471     if mano_response.status_code == 200:
472         print content['result']
473     else:
474         print content['error']['description']
475     return result
476
477 def scenario_deploy(args):
478     print "This command is deprecated, use 'openmano instance-scenario-create --scenario %s --name %s' instead!!!" % (args.scenario, args.name)
479     print
480     args.file = None
481     args.netmap_use = None
482     args.netmap_create = None
483     return instance_create(args)
484
485 #     #print "scenario-deploy",args
486 #     headers_req = {'content-type': 'application/json'}
487 #     action = {}
488 #     actionCmd="start"
489 #     if args.nostart:
490 #         actionCmd="reserve"
491 #     action[actionCmd] = {}
492 #     action[actionCmd]["instance_name"] = args.name
493 #     if args.datacenter != None:
494 #         action[actionCmd]["datacenter"] = args.datacenter
495 #     elif mano_datacenter != None:
496 #         action[actionCmd]["datacenter"] = mano_datacenter
497 #         
498 #     if args.description:
499 #         action[actionCmd]["description"] = args.description
500 #     payload_req = json.dumps(action, indent=4)
501 #     #print payload_req
502
503 #     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, mano_tenant, args.scenario)
504 #     logger.debug("openmano request: %s", payload_req)
505 #     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
506 #     logger.debug("openmano response: %s", mano_response.text )
507 #     if args.verbose==None:
508 #         args.verbose=0
509 #     
510 #     result = 0 if mano_response.status_code==200 else mano_response.status_code
511 #     content = mano_response.json()
512 #     #print json.dumps(content, indent=4)
513 #     if args.verbose >= 3:
514 #         print yaml.safe_dump(content, indent=4, default_flow_style=False)
515 #         return result
516
517 #     if mano_response.status_code == 200:
518 #         myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
519 #         if args.verbose >=1:
520 #             myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
521 #         if args.verbose >=2:
522 #             myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
523 #         print myoutput
524 #         print ""
525 #         print "To check the status, run the following command:"
526 #         print "openmano instance-scenario-list <instance_id>"
527 #     else:
528 #         print content['error']['description']
529 #     return result
530
531 def scenario_verify(args):
532     #print "scenario-verify",args
533     headers_req = {'content-type': 'application/json'}
534     action = {}
535     action["verify"] = {}
536     action["verify"]["instance_name"] = "scen-verify-return5"
537     payload_req = json.dumps(action, indent=4)
538     #print payload_req
539
540     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, mano_tenant, args.scenario)
541     logger.debug("openmano request: %s", payload_req)
542     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
543     logger.debug("openmano response: %s", mano_response.text )
544     
545     result = 0 if mano_response.status_code==200 else mano_response.status_code
546     content = mano_response.json()
547     #print json.dumps(content, indent=4)
548     if mano_response.status_code == 200:
549         print content['result']
550     else:
551         print content['error']['description']
552     return result
553
554 def instance_create(args):
555     tenant = _get_tenant()
556     headers_req = {'content-type': 'application/yaml'}
557     myInstance={"instance": {}, "schema_version": "0.1"}
558     if args.file:
559         instance_dict = _load_file_or_yaml(args.file)
560         if "instance" not in instance_dict:
561             myInstance = {"instance": instance_dict, "schema_version": "0.1"}
562         else:
563             myInstance = instance_dict
564     if args.name:
565         myInstance["instance"]['name'] = args.name
566     if args.description:
567         myInstance["instance"]['description'] = args.description
568     if args.nostart:
569         myInstance["instance"]['action'] = "reserve"
570     #datacenter
571     datacenter = myInstance["instance"].get("datacenter")
572     if args.datacenter != None:
573         datacenter = args.datacenter
574     myInstance["instance"]["datacenter"] = _get_datacenter(datacenter, tenant)
575     #scenario
576     scenario = myInstance["instance"].get("scenario")
577     if args.scenario != None:
578         scenario = args.scenario
579     if not scenario:
580         print "you must provide an scenario in the file descriptor or with --scenario"
581         return -1
582     myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
583     if args.netmap_use:
584         if "networks" not in myInstance["instance"]:
585             myInstance["instance"]["networks"] = {}
586         for net in args.netmap_use:
587             net_comma_list = net.split(",")
588             for net_comma in net_comma_list:
589                 net_tuple = net_comma.split("=")
590                 if len(net_tuple) != 2:
591                     print "error at netmap-use. Expected net-scenario=net-datacenter. (%s)?" % net_comma
592                     return
593                 net_scenario   = net_tuple[0].strip()
594                 net_datacenter = net_tuple[1].strip()
595                 if net_scenario not in myInstance["instance"]["networks"]:
596                     myInstance["instance"]["networks"][net_scenario] = {} 
597                 myInstance["instance"]["networks"][net_scenario]["netmap-use"] = net_datacenter
598     if args.netmap_create:
599         if "networks" not in myInstance["instance"]:
600             myInstance["instance"]["networks"] = {}
601         for net in args.netmap_create:
602             net_comma_list = net.split(",")
603             for net_comma in net_comma_list:
604                 net_tuple = net_comma.split("=")
605                 if len(net_tuple) == 1:
606                     net_scenario   = net_tuple[0].strip()
607                     net_datacenter = None
608                 elif len(net_tuple) == 2:
609                     net_scenario   = net_tuple[0].strip()
610                     net_datacenter = net_tuple[1].strip()
611                 else:
612                     print "error at netmap-create. Expected net-scenario=net-datacenter or net-scenario. (%s)?" % net_comma
613                     return
614                 if net_scenario not in myInstance["instance"]["networks"]:
615                     myInstance["instance"]["networks"][net_scenario] = {} 
616                 myInstance["instance"]["networks"][net_scenario]["netmap-create"] = net_datacenter
617     if args.keypair:
618         if "cloud-config" not in myInstance["instance"]:
619             myInstance["instance"]["cloud-config"] = {}
620         cloud_config = myInstance["instance"]["cloud-config"]
621         for key in args.keypair:
622             index = key.find(":")
623             if index<0:
624                 if "key-pairs" not in cloud_config:
625                     cloud_config["key-pairs"] = []
626                 cloud_config["key-pairs"].append(key)
627             else:
628                 user = key[:index]
629                 key_ = key[index+1:]
630                 key_list = key_.split(",")
631                 if "users" not in cloud_config:
632                     cloud_config["users"] = []
633                 cloud_config["users"].append({"name": user, "key-pairs": key_list  })
634     if args.keypair_auto:
635         try:
636             keys=[]
637             home = os.getenv("HOME")
638             user = os.getenv("USER")
639             files = os.listdir(home+'/.ssh')
640             for file in files:
641                 if file[-4:] == ".pub":
642                     with open(home+'/.ssh/'+file, 'r') as f:
643                         keys.append(f.read())
644             if not keys:
645                 print "Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh')
646                 return 1
647         except Exception as e:
648             print "Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e))
649             return 1
650         
651         if "cloud-config" not in myInstance["instance"]:
652             myInstance["instance"]["cloud-config"] = {}
653         cloud_config = myInstance["instance"]["cloud-config"]
654         if "key-pairs" not in cloud_config:
655             cloud_config["key-pairs"] = []
656         if user:
657             if "users" not in cloud_config:
658                 cloud_config["users"] = []
659             cloud_config["users"].append({"name": user, "key-pairs": keys })                    
660                         
661     payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
662     logger.debug("openmano request: %s", payload_req)
663     URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
664     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
665     logger.debug("openmano response: %s", mano_response.text )
666     if args.verbose==None:
667         args.verbose=0
668     
669     result = 0 if mano_response.status_code==200 else mano_response.status_code
670     content = mano_response.json()
671     #print json.dumps(content, indent=4)
672     if args.verbose >= 3:
673         print yaml.safe_dump(content, indent=4, default_flow_style=False)
674         return result
675
676     if mano_response.status_code == 200:
677         myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
678         if args.verbose >=1:
679             myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
680         if args.verbose >=2:
681             myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
682         print myoutput
683     else:
684         print content['error']['description']
685     return result
686
687 def instance_scenario_list(args):
688     #print "instance-scenario-list",args
689     if args.all:
690         tenant = "any"
691     else:
692         tenant = _get_tenant()
693     if args.name:
694         toshow = _get_item_uuid("instances", args.name, tenant)
695         URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, toshow)
696     else:
697         URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
698     mano_response = requests.get(URLrequest)
699     logger.debug("openmano response: %s", mano_response.text )
700     content = mano_response.json()
701     #print json.dumps(content, indent=4)
702     if args.verbose==None:
703         args.verbose=0
704
705     result = 0 if mano_response.status_code==200 else mano_response.status_code
706     if mano_response.status_code == 200:
707         if not args.name:
708             if args.verbose >= 3:
709                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
710                 return result
711             if len(content['instances']) == 0:
712                 print "No scenario instances were found."
713                 return result
714             for instance in content['instances']:
715                 myoutput = "%s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20))
716                 if args.verbose >=1:
717                     myoutput = "%s %s" %(myoutput, instance['created_at'].ljust(20))
718                 print myoutput
719                 if args.verbose >=2:
720                     print "Description: %s" %instance['description']
721         else:
722             if args.verbose:
723                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
724                 return result
725             instance = content
726             print "%s %s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20),instance['created_at'].ljust(20))
727             print "Description: %s" %instance['description']
728             print "Template scenario id: %s" %instance['scenario_id']
729             print "Template scenario name: %s" %instance['scenario_name']
730             print "---------------------------------------"
731             print "VNF instances: %d" %len(instance['vnfs'])
732             for vnf in instance['vnfs']:
733                 #print "    %s %s Template vnf name: %s Template vnf id: %s" %(vnf['uuid'].ljust(38), vnf['name'].ljust(20), vnf['vnf_name'].ljust(20), vnf['vnf_id'].ljust(38))
734                 print "    %s %s Template vnf id: %s" %(vnf['uuid'].ljust(38), vnf['vnf_name'].ljust(20), vnf['vnf_id'].ljust(38))
735             if len(instance['nets'])>0:
736                 print "---------------------------------------"
737                 print "Internal nets:"
738                 for net in instance['nets']:
739                     if not net['external']:
740                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
741                 print "---------------------------------------"
742                 print "External nets:"
743                 for net in instance['nets']:
744                     if net['external']:
745                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
746             print "---------------------------------------"
747             print "VM instances:"
748             for vnf in instance['vnfs']:
749                 for vm in vnf['vms']:
750                     print "    %s %s %s %s VIM ID: %s" %(vm['uuid'].ljust(38), vnf['vnf_name'].ljust(20), vm['name'].ljust(20), vm['status'].ljust(12), vm['vim_vm_id'])
751     else:
752         print content['error']['description']
753         if args.verbose:
754             print yaml.safe_dump(content, indent=4, default_flow_style=False)
755     return result
756
757 def instance_scenario_status(args):
758     print "instance-scenario-status"
759     return 0
760
761 def instance_scenario_delete(args):
762     if args.all:
763         tenant = "any"
764     else:
765         tenant = _get_tenant()
766     todelete = _get_item_uuid("instances", args.name, tenant=tenant)
767     #print "instance-scenario-delete",args
768     if not args.force:
769         r = raw_input("Delete scenario instance %s (y/N)? " %(args.name))
770         if  not (len(r)>0  and r[0].lower()=="y"):
771             return
772     URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, todelete)
773     mano_response = requests.delete(URLrequest)
774     logger.debug("openmano response: %s", mano_response.text )
775     result = 0 if mano_response.status_code==200 else mano_response.status_code
776     content = mano_response.json()
777     #print json.dumps(content, indent=4)
778     if mano_response.status_code == 200:
779         print content['result']
780     else:
781         print content['error']['description']
782     return result
783
784 def instance_scenario_action(args):
785     #print "instance-scenario-action", args
786     tenant = _get_tenant()
787     toact = _get_item_uuid("instances", args.name, tenant=tenant)
788     action={}
789     action[ args.action ] = args.param
790     if args.vnf:
791         action["vnfs"] = args.vnf
792     if args.vm:
793         action["vms"] = args.vm
794     
795     headers_req = {'content-type': 'application/json'}
796     payload_req = json.dumps(action, indent=4)
797     URLrequest = "http://%s:%s/openmano/%s/instances/%s/action" %(mano_host, mano_port, tenant, toact)
798     logger.debug("openmano request: %s", payload_req)
799     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
800     logger.debug("openmano response: %s", mano_response.text )
801     result = 0 if mano_response.status_code==200 else mano_response.status_code
802     content = mano_response.json()
803     #print json.dumps(content, indent=4)
804     if mano_response.status_code == 200:
805         if args.verbose:
806             print yaml.safe_dump(content, indent=4, default_flow_style=False)
807             return result
808         for uuid,c in content.iteritems():
809             print "%s %s %s" %(uuid.ljust(38), c['name'].ljust(20),c['description'].ljust(20))
810     else:
811         print content['error']['description']
812     return result
813
814
815 def instance_vnf_list(args):
816     print "instance-vnf-list"
817     return 0
818
819 def instance_vnf_status(args):
820     print "instance-vnf-status"
821     return 0
822
823 def tenant_create(args):
824     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
825     tenant_dict={"name": args.name}
826     if args.description!=None:
827         tenant_dict["description"] = args.description 
828     payload_req = json.dumps( {"tenant": tenant_dict })
829     
830     #print payload_req
831         
832     URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
833     logger.debug("openmano request: %s", payload_req)
834     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
835     logger.debug("openmano response: %s", mano_response.text )
836     return _print_verbose(mano_response, args.verbose)
837
838 def tenant_list(args):
839     #print "tenant-list",args
840     if args.name:
841         toshow = _get_item_uuid("tenants", args.name)
842         URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, toshow)
843     else:
844         URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
845     mano_response = requests.get(URLrequest)
846     logger.debug("openmano response: %s", mano_response.text )
847     if args.verbose==None:
848         args.verbose=0
849     if args.name!=None:
850         args.verbose += 1
851     return _print_verbose(mano_response, args.verbose)
852
853 def tenant_delete(args):
854     #print "tenant-delete",args
855     todelete = _get_item_uuid("tenants", args.name)
856     if not args.force:
857         r = raw_input("Delete tenant %s (y/N)? " %(args.name))
858         if  not (len(r)>0  and r[0].lower()=="y"):
859             return 0
860     URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, todelete)
861     mano_response = requests.delete(URLrequest)
862     logger.debug("openmano response: %s", mano_response.text )
863     result = 0 if mano_response.status_code==200 else mano_response.status_code
864     content = mano_response.json()
865     #print json.dumps(content, indent=4)
866     if mano_response.status_code == 200:
867         print content['result']
868     else:
869         print content['error']['description']
870     return result
871
872 def datacenter_attach(args):
873     tenant = _get_tenant()
874     datacenter = _get_datacenter(args.name)
875     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
876     
877     datacenter_dict={}
878     if args.vim_tenant_id != None:
879         datacenter_dict['vim_tenant'] = args.vim_tenant_id
880     if args.vim_tenant_name != None:
881         datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
882     if args.user != None:
883         datacenter_dict['vim_username'] = args.user
884     if args.password != None:
885         datacenter_dict['vim_password'] = args.password
886     payload_req = json.dumps( {"datacenter": datacenter_dict })
887     
888     #print payload_req
889         
890     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
891     logger.debug("openmano request: %s", payload_req)
892     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
893     logger.debug("openmano response: %s", mano_response.text )
894     result = _print_verbose(mano_response, args.verbose)
895     #provide addional information if error
896     if mano_response.status_code != 200:
897         content = mano_response.json()
898         if "already in use for  'name'" in content['error']['description'] and \
899                 "to database vim_tenants table" in content['error']['description']:
900             print "Try to specify a different name with --vim-tenant-name"
901     return result
902
903 def datacenter_detach(args):
904     if args.all:
905         tenant = "any"
906     else:
907         tenant = _get_tenant()
908     datacenter = _get_datacenter(args.name, tenant)
909     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
910     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
911     mano_response = requests.delete(URLrequest, headers=headers_req)
912     logger.debug("openmano response: %s", mano_response.text )
913     content = mano_response.json()
914     #print json.dumps(content, indent=4)
915     result = 0 if mano_response.status_code==200 else mano_response.status_code
916     if mano_response.status_code == 200:
917         print content['result']
918     else:
919         print content['error']['description']
920     return result
921
922 def datacenter_create(args):
923     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
924     datacenter_dict={"name": args.name, "vim_url": args.url}
925     if args.description!=None:
926         datacenter_dict["description"] = args.description 
927     if args.type!=None:
928         datacenter_dict["type"] = args.type 
929     if args.url!=None:
930         datacenter_dict["vim_url_admin"] = args.url_admin 
931     if args.config!=None:
932         datacenter_dict["config"] = _load_file_or_yaml(args.config) 
933     payload_req = json.dumps( {"datacenter": datacenter_dict })
934     
935     #print payload_req
936         
937     URLrequest = "http://%s:%s/openmano/datacenters" %(mano_host, mano_port)
938     logger.debug("openmano request: %s", payload_req)
939     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
940     logger.debug("openmano response: %s", mano_response.text )
941     return _print_verbose(mano_response, args.verbose)
942
943 def datacenter_delete(args):
944     #print "datacenter-delete",args
945     todelete = _get_item_uuid("datacenters", args.name, "any")
946     if not args.force:
947         r = raw_input("Delete datacenter %s (y/N)? " %(args.name))
948         if  not (len(r)>0  and r[0].lower()=="y"):
949             return 0
950     URLrequest = "http://%s:%s/openmano/datacenters/%s" %(mano_host, mano_port, todelete)
951     mano_response = requests.delete(URLrequest)
952     logger.debug("openmano response: %s", mano_response.text )
953     result = 0 if mano_response.status_code==200 else mano_response.status_code
954     content = mano_response.json()
955     #print json.dumps(content, indent=4)
956     if mano_response.status_code == 200:
957         print content['result']
958     else:
959         print content['error']['description']
960     return result
961
962 def datacenter_list(args):
963     #print "datacenter-list",args
964     tenant='any' if args.all else _get_tenant()
965     
966     if args.name:
967         toshow = _get_item_uuid("datacenters", args.name, tenant) 
968         URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, toshow)
969     else:
970         URLrequest = "http://%s:%s/openmano/%s/datacenters" %(mano_host, mano_port, tenant)
971     mano_response = requests.get(URLrequest)
972     logger.debug("openmano response: %s", mano_response.text )
973     if args.verbose==None:
974         args.verbose=0
975     if args.name!=None:
976         args.verbose += 1
977     return _print_verbose(mano_response, args.verbose)
978
979 def vim_action(args):
980     #print "datacenter-net-action",args
981     tenant = _get_tenant()
982     datacenter = _get_datacenter(args.datacenter, tenant)
983     if args.verbose==None:
984         args.verbose=0
985     if args.action=="list":
986         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
987         if args.name!=None:
988             args.verbose += 1
989             URLrequest += "/" + args.name
990         mano_response = requests.get(URLrequest)
991         logger.debug("openmano response: %s", mano_response.text )
992         return _print_verbose(mano_response, args.verbose)
993     elif args.action=="delete":
994         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss/%s" %(mano_host, mano_port, tenant, datacenter, args.item, args.name)
995         mano_response = requests.delete(URLrequest)
996         logger.debug("openmano response: %s", mano_response.text )
997         result = 0 if mano_response.status_code==200 else mano_response.status_code
998         content = mano_response.json()
999         #print json.dumps(content, indent=4)
1000         if mano_response.status_code == 200:
1001             print content['result']
1002         else:
1003             print content['error']['description']
1004         return result
1005     elif args.action=="create":
1006         headers_req = {'content-type': 'application/yaml'}
1007         if args.file:
1008             create_dict = _load_file_or_yaml(args.file)
1009             if args.item not in create_dict:
1010                 create_dict = {args.item: create_dict}
1011         else:
1012             create_dict = {args.item:{}}
1013         if args.name:
1014             create_dict[args.item]['name'] = args.name
1015         #if args.description:
1016         #    create_dict[args.item]['description'] = args.description
1017         if args.item=="vim-net":
1018             if args.bind_net:
1019                 create_dict[args.item]['bind_net'] = args.bind_net
1020             if args.bind_type:
1021                 create_dict[args.item]['bind_type'] = args.bind_type
1022             if args.shared:
1023                 create_dict[args.item]['shared'] = args.shared
1024         if "name" not in create_dict[args.item]:
1025             print "You must provide a name in the descriptor file or with the --name option"
1026             return
1027         payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
1028         logger.debug("openmano request: %s", payload_req)
1029         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, mano_tenant, datacenter, args.item)
1030         mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
1031         logger.debug("openmano response: %s", mano_response.text )
1032         if args.verbose==None:
1033             args.verbose=0
1034         return _print_verbose(mano_response, args.verbose)
1035
1036
1037 def datacenter_net_action(args):
1038     if args.action == "net-update":
1039         print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-import' instead!!!"
1040         print
1041         args.action = "netmap-delete"
1042         args.netmap = None
1043         args.all = True
1044         r = datacenter_netmap_action(args)
1045         if r == 0:
1046             args.force = True
1047             args.action = "netmap-import"
1048             r = datacenter_netmap_action(args)
1049         return r
1050
1051     if args.action == "net-edit":
1052         args.netmap = args.net
1053         args.name = None
1054     elif args.action == "net-list":
1055         args.netmap = None
1056     elif args.action == "net-delete":
1057         args.netmap = args.net
1058         args.all = False
1059           
1060     args.action = "netmap" + args.action[3:]
1061     args.vim_name=None
1062     args.vim_id=None
1063     print "This command is deprecated, use 'openmano datacenter-%s' instead!!!" % args.action
1064     print
1065     return datacenter_netmap_action(args)
1066
1067 def datacenter_netmap_action(args):
1068     tenant = _get_tenant()
1069     datacenter = _get_datacenter(args.datacenter, tenant)
1070     #print "datacenter_netmap_action",args
1071     payload_req = None
1072     if args.verbose==None:
1073         args.verbose=0
1074     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1075     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/netmaps" %(mano_host, mano_port, tenant, datacenter)
1076         
1077     if args.action=="netmap-list":
1078         if args.netmap:
1079             URLrequest += "/" + args.netmap
1080             args.verbose += 1
1081         mano_response = requests.get(URLrequest)
1082             
1083     elif args.action=="netmap-delete":
1084         if args.netmap and args.all:
1085             print "you can not use a netmap name and the option --all at the same time"
1086             return 1
1087         if args.netmap:
1088             force_text= "Delete default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter)
1089             URLrequest += "/" + args.netmap
1090         elif args.all: 
1091             force_text="Delete all default netmaps from datacenter '%s' (y/N)? " % (datacenter)
1092         else:
1093             print "you must specify a netmap name or the option --all"
1094             return 1
1095         if not args.force:
1096             r = raw_input(force_text)
1097             if  len(r)>0  and r[0].lower()=="y":
1098                 pass
1099             else:
1100                 return 0
1101         mano_response = requests.delete(URLrequest, headers=headers_req)
1102     elif args.action=="netmap-import":
1103         if not args.force:
1104             r = raw_input("Create all the available networks from datacenter '%s' as default netmaps (y/N)? " % (datacenter))
1105             if  len(r)>0  and r[0].lower()=="y":
1106                 pass
1107             else:
1108                 return 0
1109         URLrequest += "/upload"
1110         mano_response = requests.post(URLrequest, headers=headers_req)
1111     elif args.action=="netmap-edit" or args.action=="netmap-create":
1112         if args.file:
1113             payload = _load_file_or_yaml(args.file)
1114         else:
1115             payload = {}
1116         if "netmap" not in payload:
1117             payload = {"netmap": payload}
1118         if args.name:
1119             payload["netmap"]["name"] = args.name
1120         if args.vim_id:
1121             payload["netmap"]["vim_id"] = args.vim_id
1122         if args.action=="netmap-create" and args.vim_name:
1123             payload["netmap"]["vim_name"] = args.vim_name
1124         payload_req = json.dumps(payload)
1125         logger.debug("openmano request: %s", payload_req)
1126         
1127         if args.action=="netmap-edit" and not args.force:
1128             if len(payload["netmap"]) == 0:
1129                 print "You must supply some parameter to edit"
1130                 return 1
1131             r = raw_input("Edit default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter))
1132             if  len(r)>0  and r[0].lower()=="y":
1133                 pass
1134             else:
1135                 return 0
1136             URLrequest += "/" + args.netmap
1137             mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1138         else: #netmap-create
1139             if "vim_name" not in payload["netmap"] and "vim_id" not in payload["netmap"]:
1140                 print "You must supply either --vim-id or --vim-name option; or include one of them in the file descriptor"
1141                 return 1
1142             mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1143
1144     logger.debug("openmano response: %s", mano_response.text )
1145     return _print_verbose(mano_response, args.verbose)
1146
1147 def element_edit(args):
1148     element = _get_item_uuid(args.element, args.name)
1149     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1150     URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, args.element, element)
1151     payload=_load_file_or_yaml(args.file)
1152     if args.element[:-1] not in payload:
1153         payload = {args.element[:-1]: payload }
1154     payload_req = json.dumps(payload)
1155     
1156     #print payload_req
1157     if not args.force or (args.name==None and args.filer==None):
1158         r = raw_input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
1159         if  len(r)>0  and r[0].lower()=="y":
1160             pass
1161         else:
1162             return 0
1163     logger.debug("openmano request: %s", payload_req)
1164     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1165     logger.debug("openmano response: %s", mano_response.text )
1166     if args.verbose==None:
1167         args.verbose=0
1168     if args.name!=None:
1169         args.verbose += 1
1170     return _print_verbose(mano_response, args.verbose)
1171
1172
1173 global mano_host
1174 global mano_port
1175 global mano_tenant
1176
1177 if __name__=="__main__":
1178     
1179     mano_tenant = os.getenv('OPENMANO_TENANT', None)
1180     mano_host = os.getenv('OPENMANO_HOST',"localhost")
1181     mano_port = os.getenv('OPENMANO_PORT',"9090")
1182     mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
1183     
1184     main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
1185     main_parser.add_argument('--version', action='version', version='%(prog)s ' + __version__ )
1186     
1187     subparsers = main_parser.add_subparsers(help='commands')
1188     
1189     parent_parser = argparse.ArgumentParser(add_help=False)
1190     parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
1191     parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1192
1193     config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
1194     config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
1195     config_parser.set_defaults(func=config)
1196
1197     vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
1198     vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
1199     vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1200     vnf_create_parser.add_argument("--description", action="store", help="description of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1201     vnf_create_parser.add_argument("--image-path", action="store",  help="change image path locations (overwritten)")
1202     vnf_create_parser.set_defaults(func=vnf_create)
1203
1204     vnf_list_parser = subparsers.add_parser('vnf-list', parents=[parent_parser], help="lists information about a vnf")
1205     vnf_list_parser.add_argument("name", nargs='?', help="name of the VNF")
1206     vnf_list_parser.add_argument("-a", "--all", action="store_true", help="shows all vnfs, not only the owned or public ones")
1207     #vnf_list_parser.add_argument('--descriptor', help="prints the VNF descriptor", action="store_true")
1208     vnf_list_parser.set_defaults(func=vnf_list)
1209     
1210     vnf_delete_parser = subparsers.add_parser('vnf-delete', parents=[parent_parser], help="deletes a vnf from the catalogue")
1211     vnf_delete_parser.add_argument("name", action="store", help="name or uuid of the VNF to be deleted")
1212     vnf_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1213     vnf_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1214     vnf_delete_parser.set_defaults(func=vnf_delete)
1215     
1216     scenario_create_parser = subparsers.add_parser('scenario-create', parents=[parent_parser], help="adds a scenario into the OPENMANO DB")
1217     scenario_create_parser.add_argument("file", action="store", help="location of the YAML file describing the scenario").completer = FilesCompleter
1218     scenario_create_parser.add_argument("--name", action="store", help="name of the scenario (if it exists in the YAML scenario, it is overwritten)")
1219     scenario_create_parser.add_argument("--description", action="store", help="description of the scenario (if it exists in the YAML scenario, it is overwritten)")
1220     scenario_create_parser.set_defaults(func=scenario_create)
1221
1222     scenario_list_parser = subparsers.add_parser('scenario-list', parents=[parent_parser], help="lists information about a scenario")
1223     scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario")
1224     #scenario_list_parser.add_argument('--descriptor', help="prints the scenario descriptor", action="store_true")
1225     scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all scenarios, not only the owned or public ones")
1226     scenario_list_parser.set_defaults(func=scenario_list)
1227     
1228     scenario_delete_parser = subparsers.add_parser('scenario-delete', parents=[parent_parser], help="deletes a scenario from the OPENMANO DB")
1229     scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario to be deleted")
1230     scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1231     scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1232     scenario_delete_parser.set_defaults(func=scenario_delete)
1233
1234     scenario_deploy_parser = subparsers.add_parser('scenario-deploy', parents=[parent_parser], help="deploys a scenario")
1235     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be deployed")
1236     scenario_deploy_parser.add_argument("name", action="store", help="name of the instance")
1237     scenario_deploy_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1238     scenario_deploy_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1239     scenario_deploy_parser.add_argument("--description", action="store", help="description of the instance")
1240     scenario_deploy_parser.set_defaults(func=scenario_deploy)
1241     
1242     scenario_deploy_parser = subparsers.add_parser('scenario-verify', help="verifies if a scenario can be deployed (deploys it and deletes it)")
1243     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be verified")
1244     scenario_deploy_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1245     scenario_deploy_parser.set_defaults(func=scenario_verify)
1246     
1247     instance_scenario_create_parser = subparsers.add_parser('instance-scenario-create', parents=[parent_parser], help="deploys a scenario")
1248     instance_scenario_create_parser.add_argument("file", nargs='?', help="descriptor of the instance. Must be a file or yaml/json text")
1249     instance_scenario_create_parser.add_argument("--scenario", action="store", help="name or uuid of the scenario to be deployed")
1250     instance_scenario_create_parser.add_argument("--name", action="store", help="name of the instance")
1251     instance_scenario_create_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1252     instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1253     instance_scenario_create_parser.add_argument("--netmap-use", action="append", type=str, dest="netmap_use", help="indicates a datacenter network to map a scenario network 'scenario-network=datacenter-network'. Can be used several times")
1254     instance_scenario_create_parser.add_argument("--netmap-create", action="append", type=str, dest="netmap_create", help="the scenario network must be created at datacenter 'scenario-network[=datacenter-network-name]' . Can be used several times")
1255     instance_scenario_create_parser.add_argument("--keypair", action="append", type=str, dest="keypair", help="public key for ssh access. Format '[user:]key1[,key2...]'. Can be used several times")
1256     instance_scenario_create_parser.add_argument("--keypair-auto", action="store_true", dest="keypair_auto", help="Inject the user ssh-keys found at $HOME/.ssh directory")
1257     instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
1258     instance_scenario_create_parser.set_defaults(func=instance_create)
1259
1260     instance_scenario_list_parser = subparsers.add_parser('instance-scenario-list', parents=[parent_parser], help="lists information about a scenario instance")
1261     instance_scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario instance")
1262     instance_scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all instance-scenarios, not only the owned")
1263     instance_scenario_list_parser.set_defaults(func=instance_scenario_list)
1264
1265     instance_scenario_delete_parser = subparsers.add_parser('instance-scenario-delete', parents=[parent_parser], help="deletes a scenario instance (and deletes all VM and net instances in VIM)")
1266     instance_scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario instance to be deleted")
1267     instance_scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1268     instance_scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1269     instance_scenario_delete_parser.set_defaults(func=instance_scenario_delete)
1270     
1271     instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
1272     instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1273     instance_scenario_action_parser.add_argument("action", action="store", type=str, \
1274             choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console"],\
1275             help="action to send")
1276     instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console type (novnc, ...), reboot type (TODO)")
1277     instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
1278     instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
1279     instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
1280
1281     #instance_scenario_status_parser = subparsers.add_parser('instance-scenario-status', help="show the status of a scenario instance")
1282     #instance_scenario_status_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1283     #instance_scenario_status_parser.set_defaults(func=instance_scenario_status)
1284     
1285     tenant_create_parser = subparsers.add_parser('tenant-create', parents=[parent_parser], help="creates a new tenant")
1286     tenant_create_parser.add_argument("name", action="store", help="name for the tenant")
1287     tenant_create_parser.add_argument("--description", action="store", help="description of the tenant")
1288     tenant_create_parser.set_defaults(func=tenant_create)
1289
1290     tenant_delete_parser = subparsers.add_parser('tenant-delete', parents=[parent_parser], help="deletes a tenant from the catalogue")
1291     tenant_delete_parser.add_argument("name", action="store", help="name or uuid of the tenant to be deleted")
1292     tenant_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1293     tenant_delete_parser.set_defaults(func=tenant_delete)
1294
1295     tenant_list_parser = subparsers.add_parser('tenant-list', parents=[parent_parser], help="lists information about a tenant")
1296     tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
1297     tenant_list_parser.set_defaults(func=tenant_list)
1298
1299     item_list=('tenant','datacenter') #put tenant before so that help appear in order
1300     for item in item_list:
1301         element_edit_parser = subparsers.add_parser(item+'-edit', parents=[parent_parser], help="edits one "+item)
1302         element_edit_parser.add_argument("name", help="name or uuid of the "+item)
1303         element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1304         element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1305         element_edit_parser.set_defaults(func=element_edit, element=item + 's')
1306
1307     datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
1308     datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
1309     datacenter_create_parser.add_argument("url", action="store", help="url for the datacenter")
1310     datacenter_create_parser.add_argument("--url_admin", action="store", help="url for administration for the datacenter")
1311     datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
1312     datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1313     datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
1314     datacenter_create_parser.set_defaults(func=datacenter_create)
1315
1316     datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
1317     datacenter_delete_parser.add_argument("name", action="store", help="name or uuid of the datacenter to be deleted")
1318     datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1319     datacenter_delete_parser.set_defaults(func=datacenter_delete)
1320
1321     datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
1322     datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
1323     datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
1324     datacenter_list_parser.set_defaults(func=datacenter_list)
1325
1326     datacenter_attach_parser = subparsers.add_parser('datacenter-attach', parents=[parent_parser], help="associates a datacenter to the operating tenant")
1327     datacenter_attach_parser.add_argument("name", help="name or uuid of the datacenter")
1328     datacenter_attach_parser.add_argument('--vim-tenant-id', action='store', help="specify a datacenter tenant to use. A new one is created by default")
1329     datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1330     datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1331     datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1332     datacenter_attach_parser.set_defaults(func=datacenter_attach)
1333
1334     datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
1335     datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
1336     datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
1337     datacenter_detach_parser.set_defaults(func=datacenter_detach)
1338
1339
1340     action_dict={'net-update': 'retrieves external networks from datacenter',
1341                  'net-edit': 'edits an external network',
1342                  'net-delete': 'deletes an external network',
1343                  'net-list': 'lists external networks from a datacenter'
1344                  }
1345     for item in action_dict:
1346         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1347         datacenter_action_parser.add_argument("datacenter", help="name or uuid of the datacenter")
1348         if item=='net-edit' or item=='net-delete':
1349             datacenter_action_parser.add_argument("net", help="name or uuid of the datacenter net")
1350         if item=='net-edit':
1351             datacenter_action_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1352         if item!='net-list':
1353             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1354         datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
1355
1356
1357     action_dict={'netmap-import': 'create network senario netmap base on the datacenter networks',
1358                  'netmap-create': 'create a new network senario netmap',
1359                  'netmap-edit':   'edit name of a network senario netmap',
1360                  'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
1361                  'netmap-list':   'list/show network scenario netmaps'
1362                  }
1363     for item in action_dict:
1364         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1365         datacenter_action_parser.add_argument("--datacenter", help="name or uuid of the datacenter")
1366         #if item=='net-add':
1367         #    datacenter_action_parser.add_argument("net", help="name of the network")
1368         if item=='netmap-delete':
1369             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to delete")
1370             datacenter_action_parser.add_argument("--all", action="store_true", help="delete all netmap of this datacenter")
1371             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1372         if item=='netmap-edit':
1373             datacenter_action_parser.add_argument("netmap", help="name or uuid of the datacenter netmap do edit")
1374             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file with the changes").completer = FilesCompleter
1375             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap")
1376             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1377             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1378         if item=='netmap-list':
1379             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to show")
1380         if item=='netmap-create':
1381             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file descriptor with the changes").completer = FilesCompleter
1382             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
1383             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1384             datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
1385         if item=='netmap-import':
1386             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1387         datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)
1388     
1389     for item in ("network", "tenant"):
1390         if item=="network":
1391             commnad_name = 'vim-net'
1392         else:
1393             commnad_name = 'vim-'+item
1394         vim_item_list_parser = subparsers.add_parser(commnad_name + '-list', parents=[parent_parser], help="list the vim " + item + "s")
1395         vim_item_list_parser.add_argument("name", nargs='?', help="name or uuid of the " + item + "s")
1396         vim_item_list_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1397         vim_item_list_parser.set_defaults(func=vim_action, item=item, action="list")
1398
1399         vim_item_del_parser = subparsers.add_parser(commnad_name + '-delete', parents=[parent_parser], help="list the vim " + item + "s")
1400         vim_item_del_parser.add_argument("name", help="name or uuid of the " + item + "s")
1401         vim_item_del_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1402         vim_item_del_parser.set_defaults(func=vim_action, item=item, action="delete")
1403
1404         vim_item_create_parser = subparsers.add_parser(commnad_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
1405         vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the %s. Must be a file or yaml/json text" % item).completer = FilesCompleter
1406         vim_item_create_parser.add_argument("--name", action="store", help="name of the %s" % item  )
1407         vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1408         if item=="network":
1409             vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
1410             vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
1411             vim_item_create_parser.add_argument("--bind-net", action="store", help="For openvim datacenter type, net to be bind to, for vlan type, use sufix ':<vlan_tag>'")
1412         else:
1413             vim_item_create_parser.add_argument("--description", action="store", help="description of the %s" % item)
1414         vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
1415
1416     argcomplete.autocomplete(main_parser)
1417     
1418     try:
1419         args = main_parser.parse_args()
1420         #logging info
1421         level = logging.CRITICAL
1422         streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
1423         if "debug" in args and args.debug:
1424             level = logging.DEBUG
1425         logging.basicConfig(format=streamformat, level= level)
1426         logger = logging.getLogger('mano')
1427         logger.setLevel(level)
1428         result = args.func(args)
1429         if result == None:
1430             result = 0
1431         #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
1432     except (requests.exceptions.ConnectionError):
1433         print "Connection error: not possible to contact OPENMANO-SERVER (openmanod)"
1434         result = -2
1435     except (KeyboardInterrupt):
1436         print 'Exiting openmano'
1437         result = -3
1438     except (SystemExit, ArgumentParserError):
1439         result = -4
1440     except OpenmanoCLIError as e:
1441         print str(e)
1442         result = -5
1443     
1444     #print result
1445     exit(result)
1446