Merge branch 'master' of https://osm.etsi.org/gerrit/osm/RO
[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     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                         
618     payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
619     logger.debug("openmano request: %s", payload_req)
620     URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
621     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
622     logger.debug("openmano response: %s", mano_response.text )
623     if args.verbose==None:
624         args.verbose=0
625     
626     result = 0 if mano_response.status_code==200 else mano_response.status_code
627     content = mano_response.json()
628     #print json.dumps(content, indent=4)
629     if args.verbose >= 3:
630         print yaml.safe_dump(content, indent=4, default_flow_style=False)
631         return result
632
633     if mano_response.status_code == 200:
634         myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
635         if args.verbose >=1:
636             myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
637         if args.verbose >=2:
638             myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
639         print myoutput
640     else:
641         print content['error']['description']
642     return result
643
644 def instance_scenario_list(args):
645     #print "instance-scenario-list",args
646     if args.all:
647         tenant = "any"
648     else:
649         tenant = _get_tenant()
650     if args.name:
651         toshow = _get_item_uuid("instances", args.name, tenant)
652         URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, toshow)
653     else:
654         URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
655     mano_response = requests.get(URLrequest)
656     logger.debug("openmano response: %s", mano_response.text )
657     content = mano_response.json()
658     #print json.dumps(content, indent=4)
659     if args.verbose==None:
660         args.verbose=0
661
662     result = 0 if mano_response.status_code==200 else mano_response.status_code
663     if mano_response.status_code == 200:
664         if not args.name:
665             if args.verbose >= 3:
666                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
667                 return result
668             if len(content['instances']) == 0:
669                 print "No scenario instances were found."
670                 return result
671             for instance in content['instances']:
672                 myoutput = "%s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20))
673                 if args.verbose >=1:
674                     myoutput = "%s %s" %(myoutput, instance['created_at'].ljust(20))
675                 print myoutput
676                 if args.verbose >=2:
677                     print "Description: %s" %instance['description']
678         else:
679             if args.verbose:
680                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
681                 return result
682             instance = content
683             print "%s %s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20),instance['created_at'].ljust(20))
684             print "Description: %s" %instance['description']
685             print "Template scenario id: %s" %instance['scenario_id']
686             print "Template scenario name: %s" %instance['scenario_name']
687             print "---------------------------------------"
688             print "VNF instances: %d" %len(instance['vnfs'])
689             for vnf in instance['vnfs']:
690                 #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))
691                 print "    %s %s Template vnf id: %s" %(vnf['uuid'].ljust(38), vnf['vnf_name'].ljust(20), vnf['vnf_id'].ljust(38))
692             if len(instance['nets'])>0:
693                 print "---------------------------------------"
694                 print "Internal nets:"
695                 for net in instance['nets']:
696                     if not net['external']:
697                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
698                 print "---------------------------------------"
699                 print "External nets:"
700                 for net in instance['nets']:
701                     if net['external']:
702                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
703             print "---------------------------------------"
704             print "VM instances:"
705             for vnf in instance['vnfs']:
706                 for vm in vnf['vms']:
707                     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'])
708     else:
709         print content['error']['description']
710         if args.verbose:
711             print yaml.safe_dump(content, indent=4, default_flow_style=False)
712     return result
713
714 def instance_scenario_status(args):
715     print "instance-scenario-status"
716     return 0
717
718 def instance_scenario_delete(args):
719     if args.all:
720         tenant = "any"
721     else:
722         tenant = _get_tenant()
723     todelete = _get_item_uuid("instances", args.name, tenant=tenant)
724     #print "instance-scenario-delete",args
725     if not args.force:
726         r = raw_input("Delete scenario instance %s (y/N)? " %(args.name))
727         if  not (len(r)>0  and r[0].lower()=="y"):
728             return
729     URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, todelete)
730     mano_response = requests.delete(URLrequest)
731     logger.debug("openmano response: %s", mano_response.text )
732     result = 0 if mano_response.status_code==200 else mano_response.status_code
733     content = mano_response.json()
734     #print json.dumps(content, indent=4)
735     if mano_response.status_code == 200:
736         print content['result']
737     else:
738         print content['error']['description']
739     return result
740
741 def instance_scenario_action(args):
742     #print "instance-scenario-action", args
743     tenant = _get_tenant()
744     toact = _get_item_uuid("instances", args.name, tenant=tenant)
745     action={}
746     action[ args.action ] = args.param
747     if args.vnf:
748         action["vnfs"] = args.vnf
749     if args.vm:
750         action["vms"] = args.vm
751     
752     headers_req = {'content-type': 'application/json'}
753     payload_req = json.dumps(action, indent=4)
754     URLrequest = "http://%s:%s/openmano/%s/instances/%s/action" %(mano_host, mano_port, tenant, toact)
755     logger.debug("openmano request: %s", payload_req)
756     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
757     logger.debug("openmano response: %s", mano_response.text )
758     result = 0 if mano_response.status_code==200 else mano_response.status_code
759     content = mano_response.json()
760     #print json.dumps(content, indent=4)
761     if mano_response.status_code == 200:
762         if args.verbose:
763             print yaml.safe_dump(content, indent=4, default_flow_style=False)
764             return result
765         for uuid,c in content.iteritems():
766             print "%s %s %s" %(uuid.ljust(38), c['name'].ljust(20),c['description'].ljust(20))
767     else:
768         print content['error']['description']
769     return result
770
771
772 def instance_vnf_list(args):
773     print "instance-vnf-list"
774     return 0
775
776 def instance_vnf_status(args):
777     print "instance-vnf-status"
778     return 0
779
780 def tenant_create(args):
781     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
782     tenant_dict={"name": args.name}
783     if args.description!=None:
784         tenant_dict["description"] = args.description 
785     payload_req = json.dumps( {"tenant": tenant_dict })
786     
787     #print payload_req
788         
789     URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
790     logger.debug("openmano request: %s", payload_req)
791     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
792     logger.debug("openmano response: %s", mano_response.text )
793     return _print_verbose(mano_response, args.verbose)
794
795 def tenant_list(args):
796     #print "tenant-list",args
797     if args.name:
798         toshow = _get_item_uuid("tenants", args.name)
799         URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, toshow)
800     else:
801         URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
802     mano_response = requests.get(URLrequest)
803     logger.debug("openmano response: %s", mano_response.text )
804     if args.verbose==None:
805         args.verbose=0
806     if args.name!=None:
807         args.verbose += 1
808     return _print_verbose(mano_response, args.verbose)
809
810 def tenant_delete(args):
811     #print "tenant-delete",args
812     todelete = _get_item_uuid("tenants", args.name)
813     if not args.force:
814         r = raw_input("Delete tenant %s (y/N)? " %(args.name))
815         if  not (len(r)>0  and r[0].lower()=="y"):
816             return 0
817     URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, todelete)
818     mano_response = requests.delete(URLrequest)
819     logger.debug("openmano response: %s", mano_response.text )
820     result = 0 if mano_response.status_code==200 else mano_response.status_code
821     content = mano_response.json()
822     #print json.dumps(content, indent=4)
823     if mano_response.status_code == 200:
824         print content['result']
825     else:
826         print content['error']['description']
827     return result
828
829 def datacenter_attach(args):
830     tenant = _get_tenant()
831     datacenter = _get_datacenter(args.name)
832     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
833     
834     datacenter_dict={}
835     if args.vim_tenant_id != None:
836         datacenter_dict['vim_tenant'] = args.vim_tenant_id
837     if args.vim_tenant_name != None:
838         datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
839     if args.user != None:
840         datacenter_dict['vim_username'] = args.user
841     if args.password != None:
842         datacenter_dict['vim_password'] = args.password
843     payload_req = json.dumps( {"datacenter": datacenter_dict })
844     
845     #print payload_req
846         
847     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
848     logger.debug("openmano request: %s", payload_req)
849     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
850     logger.debug("openmano response: %s", mano_response.text )
851     result = _print_verbose(mano_response, args.verbose)
852     #provide addional information if error
853     if mano_response.status_code != 200:
854         content = mano_response.json()
855         if "already in use for  'name'" in content['error']['description'] and \
856                 "to database vim_tenants table" in content['error']['description']:
857             print "Try to specify a different name with --vim-tenant-name"
858     return result
859
860 def datacenter_detach(args):
861     if args.all:
862         tenant = "any"
863     else:
864         tenant = _get_tenant()
865     datacenter = _get_datacenter(args.name, tenant)
866     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
867     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
868     mano_response = requests.delete(URLrequest, headers=headers_req)
869     logger.debug("openmano response: %s", mano_response.text )
870     content = mano_response.json()
871     #print json.dumps(content, indent=4)
872     result = 0 if mano_response.status_code==200 else mano_response.status_code
873     if mano_response.status_code == 200:
874         print content['result']
875     else:
876         print content['error']['description']
877     return result
878
879 def datacenter_create(args):
880     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
881     datacenter_dict={"name": args.name, "vim_url": args.url}
882     if args.description!=None:
883         datacenter_dict["description"] = args.description 
884     if args.type!=None:
885         datacenter_dict["type"] = args.type 
886     if args.url!=None:
887         datacenter_dict["vim_url_admin"] = args.url_admin 
888     if args.config!=None:
889         datacenter_dict["config"] = _load_file_or_yaml(args.config) 
890     payload_req = json.dumps( {"datacenter": datacenter_dict })
891     
892     #print payload_req
893         
894     URLrequest = "http://%s:%s/openmano/datacenters" %(mano_host, mano_port)
895     logger.debug("openmano request: %s", payload_req)
896     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
897     logger.debug("openmano response: %s", mano_response.text )
898     return _print_verbose(mano_response, args.verbose)
899
900 def datacenter_delete(args):
901     #print "datacenter-delete",args
902     todelete = _get_item_uuid("datacenters", args.name, "any")
903     if not args.force:
904         r = raw_input("Delete datacenter %s (y/N)? " %(args.name))
905         if  not (len(r)>0  and r[0].lower()=="y"):
906             return 0
907     URLrequest = "http://%s:%s/openmano/datacenters/%s" %(mano_host, mano_port, todelete)
908     mano_response = requests.delete(URLrequest)
909     logger.debug("openmano response: %s", mano_response.text )
910     result = 0 if mano_response.status_code==200 else mano_response.status_code
911     content = mano_response.json()
912     #print json.dumps(content, indent=4)
913     if mano_response.status_code == 200:
914         print content['result']
915     else:
916         print content['error']['description']
917     return result
918
919 def datacenter_list(args):
920     #print "datacenter-list",args
921     tenant='any' if args.all else _get_tenant()
922     
923     if args.name:
924         toshow = _get_item_uuid("datacenters", args.name, tenant) 
925         URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, toshow)
926     else:
927         URLrequest = "http://%s:%s/openmano/%s/datacenters" %(mano_host, mano_port, tenant)
928     mano_response = requests.get(URLrequest)
929     logger.debug("openmano response: %s", mano_response.text )
930     if args.verbose==None:
931         args.verbose=0
932     if args.name!=None:
933         args.verbose += 1
934     return _print_verbose(mano_response, args.verbose)
935
936 def vim_action(args):
937     #print "datacenter-net-action",args
938     tenant = _get_tenant()
939     datacenter = _get_datacenter(args.datacenter, tenant)
940     if args.verbose==None:
941         args.verbose=0
942     if args.action=="list":
943         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
944         if args.name!=None:
945             args.verbose += 1
946             URLrequest += "/" + args.name
947         mano_response = requests.get(URLrequest)
948         logger.debug("openmano response: %s", mano_response.text )
949         return _print_verbose(mano_response, args.verbose)
950     elif args.action=="delete":
951         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss/%s" %(mano_host, mano_port, tenant, datacenter, args.item, args.name)
952         mano_response = requests.delete(URLrequest)
953         logger.debug("openmano response: %s", mano_response.text )
954         result = 0 if mano_response.status_code==200 else mano_response.status_code
955         content = mano_response.json()
956         #print json.dumps(content, indent=4)
957         if mano_response.status_code == 200:
958             print content['result']
959         else:
960             print content['error']['description']
961         return result
962     elif args.action=="create":
963         headers_req = {'content-type': 'application/yaml'}
964         if args.file:
965             create_dict = _load_file_or_yaml(args.file)
966             if args.item not in create_dict:
967                 create_dict = {args.item: create_dict}
968         else:
969             create_dict = {args.item:{}}
970         if args.name:
971             create_dict[args.item]['name'] = args.name
972         #if args.description:
973         #    create_dict[args.item]['description'] = args.description
974         if args.item=="vim-net":
975             if args.bind_net:
976                 create_dict[args.item]['bind_net'] = args.bind_net
977             if args.bind_type:
978                 create_dict[args.item]['bind_type'] = args.bind_type
979             if args.shared:
980                 create_dict[args.item]['shared'] = args.shared
981         if "name" not in create_dict[args.item]:
982             print "You must provide a name in the descriptor file or with the --name option"
983             return
984         payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
985         logger.debug("openmano request: %s", payload_req)
986         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, mano_tenant, datacenter, args.item)
987         mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
988         logger.debug("openmano response: %s", mano_response.text )
989         if args.verbose==None:
990             args.verbose=0
991         return _print_verbose(mano_response, args.verbose)
992
993
994 def datacenter_net_action(args):
995     if args.action == "net-update":
996         print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-upload' instead!!!"
997         print
998         args.action = "netmap-delete"
999         args.netmap = None
1000         args.all = True
1001         r = datacenter_netmap_action(args)
1002         if r == 0:
1003             args.force = True
1004             args.action = "netmap-upload"
1005             r = datacenter_netmap_action(args)
1006         return r
1007
1008     if args.action == "net-edit":
1009         args.netmap = args.net
1010         args.name = None
1011     elif args.action == "net-list":
1012         args.netmap = None
1013     elif args.action == "net-delete":
1014         args.netmap = args.net
1015         args.all = False
1016           
1017     args.action = "netmap" + args.action[3:]
1018     args.vim_name=None
1019     args.vim_id=None
1020     print "This command is deprecated, use 'openmano datacenter-%s' instead!!!" % args.action
1021     print
1022     return datacenter_netmap_action(args)
1023
1024 def datacenter_netmap_action(args):
1025     tenant = _get_tenant()
1026     datacenter = _get_datacenter(args.datacenter, tenant)
1027     #print "datacenter_netmap_action",args
1028     payload_req = None
1029     if args.verbose==None:
1030         args.verbose=0
1031     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1032     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/netmaps" %(mano_host, mano_port, tenant, datacenter)
1033         
1034     if args.action=="netmap-list":
1035         if args.netmap:
1036             URLrequest += "/" + args.netmap
1037             args.verbose += 1
1038         mano_response = requests.get(URLrequest)
1039             
1040     elif args.action=="netmap-delete":
1041         if args.netmap and args.all:
1042             print "you can not use a netmap name and the option --all at the same time"
1043             return 1
1044         if args.netmap:
1045             force_text= "Delete default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter)
1046             URLrequest += "/" + args.netmap
1047         elif args.all: 
1048             force_text="Delete all default netmaps from datacenter '%s' (y/N)? " % (datacenter)
1049         else:
1050             print "you must specify a netmap name or the option --all"
1051             return 1
1052         if not args.force:
1053             r = raw_input(force_text)
1054             if  len(r)>0  and r[0].lower()=="y":
1055                 pass
1056             else:
1057                 return 0
1058         mano_response = requests.delete(URLrequest, headers=headers_req)
1059     elif args.action=="netmap-upload":
1060         if not args.force:
1061             r = raw_input("Create all the available networks from datacenter '%s' as default netmaps (y/N)? " % (datacenter))
1062             if  len(r)>0  and r[0].lower()=="y":
1063                 pass
1064             else:
1065                 return 0
1066         URLrequest += "/upload"
1067         mano_response = requests.post(URLrequest, headers=headers_req)
1068     elif args.action=="netmap-edit" or args.action=="netmap-create":
1069         if args.file:
1070             payload = _load_file_or_yaml(args.file)
1071         else:
1072             payload = {}
1073         if "netmap" not in payload:
1074             payload = {"netmap": payload}
1075         if args.name:
1076             payload["netmap"]["name"] = args.name
1077         if args.vim_id:
1078             payload["netmap"]["vim_id"] = args.vim_id
1079         if args.action=="netmap-create" and args.vim_name:
1080             payload["netmap"]["vim_name"] = args.vim_name
1081         payload_req = json.dumps(payload)
1082         logger.debug("openmano request: %s", payload_req)
1083         
1084         if args.action=="netmap-edit" and not args.force:
1085             if len(payload["netmap"]) == 0:
1086                 print "You must supply some parameter to edit"
1087                 return 1
1088             r = raw_input("Edit default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter))
1089             if  len(r)>0  and r[0].lower()=="y":
1090                 pass
1091             else:
1092                 return 0
1093             URLrequest += "/" + args.netmap
1094             mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1095         else: #netmap-create
1096             if "vim_name" not in payload["netmap"] and "vim_id" not in payload["netmap"]:
1097                 print "You must supply either --vim-id or --vim-name option; or include one of them in the file descriptor"
1098                 return 1
1099             mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1100
1101     logger.debug("openmano response: %s", mano_response.text )
1102     return _print_verbose(mano_response, args.verbose)
1103
1104 def element_edit(args):
1105     element = _get_item_uuid(args.element, args.name)
1106     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1107     URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, args.element, element)
1108     payload=_load_file_or_yaml(args.file)
1109     if args.element[:-1] not in payload:
1110         payload = {args.element[:-1]: payload }
1111     payload_req = json.dumps(payload)
1112     
1113     #print payload_req
1114     if not args.force or (args.name==None and args.filer==None):
1115         r = raw_input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
1116         if  len(r)>0  and r[0].lower()=="y":
1117             pass
1118         else:
1119             return 0
1120     logger.debug("openmano request: %s", payload_req)
1121     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1122     logger.debug("openmano response: %s", mano_response.text )
1123     if args.verbose==None:
1124         args.verbose=0
1125     if args.name!=None:
1126         args.verbose += 1
1127     return _print_verbose(mano_response, args.verbose)
1128
1129
1130 global mano_host
1131 global mano_port
1132 global mano_tenant
1133
1134 if __name__=="__main__":
1135     
1136     mano_tenant = os.getenv('OPENMANO_TENANT', None)
1137     mano_host = os.getenv('OPENMANO_HOST',"localhost")
1138     mano_port = os.getenv('OPENMANO_PORT',"9090")
1139     mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
1140     
1141     main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
1142     main_parser.add_argument('--version', action='version', version='%(prog)s ' + __version__ )
1143     
1144     subparsers = main_parser.add_subparsers(help='commands')
1145     
1146     parent_parser = argparse.ArgumentParser(add_help=False)
1147     parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
1148     parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1149
1150     config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
1151     config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
1152     config_parser.set_defaults(func=config)
1153
1154     vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
1155     vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
1156     vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1157     vnf_create_parser.add_argument("--description", action="store", help="description of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1158     vnf_create_parser.add_argument("--image-path", action="store",  help="change image path locations (overwritten)")
1159     vnf_create_parser.set_defaults(func=vnf_create)
1160
1161     vnf_list_parser = subparsers.add_parser('vnf-list', parents=[parent_parser], help="lists information about a vnf")
1162     vnf_list_parser.add_argument("name", nargs='?', help="name of the VNF")
1163     vnf_list_parser.add_argument("-a", "--all", action="store_true", help="shows all vnfs, not only the owned or public ones")
1164     #vnf_list_parser.add_argument('--descriptor', help="prints the VNF descriptor", action="store_true")
1165     vnf_list_parser.set_defaults(func=vnf_list)
1166     
1167     vnf_delete_parser = subparsers.add_parser('vnf-delete', parents=[parent_parser], help="deletes a vnf from the catalogue")
1168     vnf_delete_parser.add_argument("name", action="store", help="name or uuid of the VNF to be deleted")
1169     vnf_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1170     vnf_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1171     vnf_delete_parser.set_defaults(func=vnf_delete)
1172     
1173     scenario_create_parser = subparsers.add_parser('scenario-create', parents=[parent_parser], help="adds a scenario into the OPENMANO DB")
1174     scenario_create_parser.add_argument("file", action="store", help="location of the YAML file describing the scenario").completer = FilesCompleter
1175     scenario_create_parser.add_argument("--name", action="store", help="name of the scenario (if it exists in the YAML scenario, it is overwritten)")
1176     scenario_create_parser.add_argument("--description", action="store", help="description of the scenario (if it exists in the YAML scenario, it is overwritten)")
1177     scenario_create_parser.set_defaults(func=scenario_create)
1178
1179     scenario_list_parser = subparsers.add_parser('scenario-list', parents=[parent_parser], help="lists information about a scenario")
1180     scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario")
1181     #scenario_list_parser.add_argument('--descriptor', help="prints the scenario descriptor", action="store_true")
1182     scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all scenarios, not only the owned or public ones")
1183     scenario_list_parser.set_defaults(func=scenario_list)
1184     
1185     scenario_delete_parser = subparsers.add_parser('scenario-delete', parents=[parent_parser], help="deletes a scenario from the OPENMANO DB")
1186     scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario to be deleted")
1187     scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1188     scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1189     scenario_delete_parser.set_defaults(func=scenario_delete)
1190
1191     scenario_deploy_parser = subparsers.add_parser('scenario-deploy', parents=[parent_parser], help="deploys a scenario")
1192     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be deployed")
1193     scenario_deploy_parser.add_argument("name", action="store", help="name of the instance")
1194     scenario_deploy_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1195     scenario_deploy_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1196     scenario_deploy_parser.add_argument("--description", action="store", help="description of the instance")
1197     scenario_deploy_parser.set_defaults(func=scenario_deploy)
1198     
1199     scenario_deploy_parser = subparsers.add_parser('scenario-verify', help="verifies if a scenario can be deployed (deploys it and deletes it)")
1200     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be verified")
1201     scenario_deploy_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1202     scenario_deploy_parser.set_defaults(func=scenario_verify)
1203     
1204     instance_scenario_create_parser = subparsers.add_parser('instance-scenario-create', parents=[parent_parser], help="deploys a scenario")
1205     instance_scenario_create_parser.add_argument("file", nargs='?', help="descriptor of the instance. Must be a file or yaml/json text")
1206     instance_scenario_create_parser.add_argument("--scenario", action="store", help="name or uuid of the scenario to be deployed")
1207     instance_scenario_create_parser.add_argument("--name", action="store", help="name of the instance")
1208     instance_scenario_create_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1209     instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1210     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")
1211     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")
1212     instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
1213     instance_scenario_create_parser.set_defaults(func=instance_create)
1214
1215     instance_scenario_list_parser = subparsers.add_parser('instance-scenario-list', parents=[parent_parser], help="lists information about a scenario instance")
1216     instance_scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario instance")
1217     instance_scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all instance-scenarios, not only the owned")
1218     instance_scenario_list_parser.set_defaults(func=instance_scenario_list)
1219
1220     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)")
1221     instance_scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario instance to be deleted")
1222     instance_scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1223     instance_scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1224     instance_scenario_delete_parser.set_defaults(func=instance_scenario_delete)
1225     
1226     instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
1227     instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1228     instance_scenario_action_parser.add_argument("action", action="store", type=str, \
1229             choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console"],\
1230             help="action to send")
1231     instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console type (novnc, ...), reboot type (TODO)")
1232     instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
1233     instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
1234     instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
1235
1236     #instance_scenario_status_parser = subparsers.add_parser('instance-scenario-status', help="show the status of a scenario instance")
1237     #instance_scenario_status_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1238     #instance_scenario_status_parser.set_defaults(func=instance_scenario_status)
1239     
1240     tenant_create_parser = subparsers.add_parser('tenant-create', parents=[parent_parser], help="creates a new tenant")
1241     tenant_create_parser.add_argument("name", action="store", help="name for the tenant")
1242     tenant_create_parser.add_argument("--description", action="store", help="description of the tenant")
1243     tenant_create_parser.set_defaults(func=tenant_create)
1244
1245     tenant_delete_parser = subparsers.add_parser('tenant-delete', parents=[parent_parser], help="deletes a tenant from the catalogue")
1246     tenant_delete_parser.add_argument("name", action="store", help="name or uuid of the tenant to be deleted")
1247     tenant_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1248     tenant_delete_parser.set_defaults(func=tenant_delete)
1249
1250     tenant_list_parser = subparsers.add_parser('tenant-list', parents=[parent_parser], help="lists information about a tenant")
1251     tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
1252     tenant_list_parser.set_defaults(func=tenant_list)
1253
1254     item_list=('tenant','datacenter') #put tenant before so that help appear in order
1255     for item in item_list:
1256         element_edit_parser = subparsers.add_parser(item+'-edit', parents=[parent_parser], help="edits one "+item)
1257         element_edit_parser.add_argument("name", help="name or uuid of the "+item)
1258         element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1259         element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1260         element_edit_parser.set_defaults(func=element_edit, element=item + 's')
1261
1262     datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
1263     datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
1264     datacenter_create_parser.add_argument("url", action="store", help="url for the datacenter")
1265     datacenter_create_parser.add_argument("--url_admin", action="store", help="url for administration for the datacenter")
1266     datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
1267     datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1268     datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
1269     datacenter_create_parser.set_defaults(func=datacenter_create)
1270
1271     datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
1272     datacenter_delete_parser.add_argument("name", action="store", help="name or uuid of the datacenter to be deleted")
1273     datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1274     datacenter_delete_parser.set_defaults(func=datacenter_delete)
1275
1276     datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
1277     datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
1278     datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
1279     datacenter_list_parser.set_defaults(func=datacenter_list)
1280
1281     datacenter_attach_parser = subparsers.add_parser('datacenter-attach', parents=[parent_parser], help="associates a datacenter to the operating tenant")
1282     datacenter_attach_parser.add_argument("name", help="name or uuid of the datacenter")
1283     datacenter_attach_parser.add_argument('--vim-tenant-id', action='store', help="specify a datacenter tenant to use. A new one is created by default")
1284     datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1285     datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1286     datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1287     datacenter_attach_parser.set_defaults(func=datacenter_attach)
1288
1289     datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
1290     datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
1291     datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
1292     datacenter_detach_parser.set_defaults(func=datacenter_detach)
1293
1294
1295     action_dict={'net-update': 'retrieves external networks from datacenter',
1296                  'net-edit': 'edits an external network',
1297                  'net-delete': 'deletes an external network',
1298                  'net-list': 'lists external networks from a datacenter'
1299                  }
1300     for item in action_dict:
1301         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1302         datacenter_action_parser.add_argument("datacenter", help="name or uuid of the datacenter")
1303         if item=='net-edit' or item=='net-delete':
1304             datacenter_action_parser.add_argument("net", help="name or uuid of the datacenter net")
1305         if item=='net-edit':
1306             datacenter_action_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1307         if item!='net-list':
1308             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1309         datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
1310
1311
1312     action_dict={'netmap-upload': 'create network senario netmap base on the datacenter networks',
1313                  'netmap-create': 'create a new network senario netmap',
1314                  'netmap-edit':   'edit name of a network senario netmap',
1315                  'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
1316                  'netmap-list':   'list/show network scenario netmaps'
1317                  }
1318     for item in action_dict:
1319         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1320         datacenter_action_parser.add_argument("--datacenter", help="name or uuid of the datacenter")
1321         #if item=='net-add':
1322         #    datacenter_action_parser.add_argument("net", help="name of the network")
1323         if item=='netmap-delete':
1324             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to delete")
1325             datacenter_action_parser.add_argument("--all", action="store_true", help="delete all netmap of this datacenter")
1326             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1327         if item=='netmap-edit':
1328             datacenter_action_parser.add_argument("netmap", help="name or uuid of the datacenter netmap do edit")
1329             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file with the changes").completer = FilesCompleter
1330             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap")
1331             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1332             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1333         if item=='netmap-list':
1334             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to show")
1335         if item=='netmap-create':
1336             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file descriptor with the changes").completer = FilesCompleter
1337             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
1338             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1339             datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
1340         if item=='netmap-upload':
1341             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1342         datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)
1343     
1344     for item in ("network", "tenant"):
1345         if item=="network":
1346             commnad_name = 'vim-net'
1347         else:
1348             commnad_name = 'vim-'+item
1349         vim_item_list_parser = subparsers.add_parser(commnad_name + '-list', parents=[parent_parser], help="list the vim " + item + "s")
1350         vim_item_list_parser.add_argument("name", nargs='?', help="name or uuid of the " + item + "s")
1351         vim_item_list_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1352         vim_item_list_parser.set_defaults(func=vim_action, item=item, action="list")
1353
1354         vim_item_del_parser = subparsers.add_parser(commnad_name + '-delete', parents=[parent_parser], help="list the vim " + item + "s")
1355         vim_item_del_parser.add_argument("name", help="name or uuid of the " + item + "s")
1356         vim_item_del_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1357         vim_item_del_parser.set_defaults(func=vim_action, item=item, action="delete")
1358
1359         vim_item_create_parser = subparsers.add_parser(commnad_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
1360         vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the %s. Must be a file or yaml/json text" % item).completer = FilesCompleter
1361         vim_item_create_parser.add_argument("--name", action="store", help="name of the %s" % item  )
1362         vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1363         if item=="network":
1364             vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
1365             vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
1366             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>'")
1367         else:
1368             vim_item_create_parser.add_argument("--description", action="store", help="description of the %s" % item)
1369         vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
1370
1371     argcomplete.autocomplete(main_parser)
1372     
1373     try:
1374         args = main_parser.parse_args()
1375         #logging info
1376         level = logging.CRITICAL
1377         streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
1378         if "debug" in args and args.debug:
1379             level = logging.DEBUG
1380         logging.basicConfig(format=streamformat, level= level)
1381         logger = logging.getLogger('mano')
1382         logger.setLevel(level)
1383         result = args.func(args)
1384         if result == None:
1385             result = 0
1386         #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
1387     except (requests.exceptions.ConnectionError):
1388         print "Connection error: not possible to contact OPENMANO-SERVER (openmanod)"
1389         result = -2
1390     except (KeyboardInterrupt):
1391         print 'Exiting openmano'
1392         result = -3
1393     except (SystemExit, ArgumentParserError):
1394         result = -4
1395     except OpenmanoCLIError as e:
1396         print str(e)
1397         result = -5
1398     
1399     #print result
1400     exit(result)
1401