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