Allow instance of only networks without scenario
[osm/RO.git] / openmano
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # PYTHON_ARGCOMPLETE_OK
4
5 ##
6 # Copyright 2015 Telefonica Investigacion 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, Pablo Montes"
30 __date__ = "$09-oct-2014 09:09:48$"
31 __version__ = "0.4.24-r534"
32 version_date = "Nov 2018"
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         uuid = None
124         for content in content_list:
125             if "uuid" in content:
126                 uuid = content['uuid']
127             elif "id" in content:
128                 uuid = content['id']
129             elif "vim_id" in content:
130                 uuid = content['vim_id']
131             name = content.get('name');
132             if not uuid:
133                 uuid = ""
134             if not name:
135                 name = ""
136             myoutput = "{:38} {:20}".format(uuid, name)
137             if content.get("status"):
138                 myoutput += " {:20}".format(content['status'])
139             elif "enabled" in content and not content["enabled"]:
140                 myoutput += " enabled=False".ljust(20)
141             if verbose_level >=1:
142                 if content.get('created_at'):
143                     myoutput += " {:20}".format(content['created_at'])
144                 if content.get('sdn_attached_ports'):
145                     #myoutput += " " + str(content['sdn_attached_ports']).ljust(20)
146                     myoutput += "\nsdn_attached_ports:\n" + yaml.safe_dump(content['sdn_attached_ports'], indent=4, default_flow_style=False)
147                 if verbose_level >=2:
148                     new_line='\n'
149                     if content.get('type'):
150                         myoutput += new_line + "  Type: {:29}".format(content['type'])
151                         new_line=''
152                     if content.get('description'):
153                         myoutput += new_line + "  Description: {:20}".format(content['description'])
154             print myoutput
155     else:
156         print content['error']['description']
157     return result
158
159 def parser_json_yaml(file_name):
160     try:
161         f = file(file_name, "r")
162         text = f.read()
163         f.close()
164     except Exception as e:
165         return (False, str(e))
166            
167     #Read and parse file
168     if file_name[-5:]=='.yaml' or file_name[-4:]=='.yml' or (file_name[-5:]!='.json' and '\t' not in text):
169         try:
170             config = yaml.load(text)
171         except yaml.YAMLError as exc:
172             error_pos = ""
173             if hasattr(exc, 'problem_mark'):
174                 mark = exc.problem_mark
175                 error_pos = " at line:%s column:%s" % (mark.line+1, mark.column+1)
176             return (False, "Error loading file '"+file_name+"' yaml format error" + error_pos)
177     else: #json
178         try:
179             config = json.loads(text) 
180         except Exception as e:
181             return (False, "Error loading file '"+file_name+"' json format error " + str(e) )
182
183     return True, config
184
185 def _load_file_or_yaml(content):
186     '''
187     'content' can be or a yaml/json file or a text containing a yaml/json text format
188     This function autodetect, trying to load and parse the file,
189     if fails trying to parse the 'content' text
190     Returns the dictionary once parsed, or print an error and finish the program
191     '''
192     #Check config file exists
193     if os.path.isfile(content):
194         r,payload = parser_json_yaml(content)
195         if not r:
196             print payload
197             exit(-1)
198     elif "{" in content or ":" in content:
199         try:
200             payload = yaml.load(content)
201         except yaml.YAMLError as exc:
202             error_pos = ""
203             if hasattr(exc, 'problem_mark'):
204                 mark = exc.problem_mark
205                 error_pos = " at position: (%s:%s)" % (mark.line+1, mark.column+1)
206             print "Error loading yaml/json text"+error_pos
207             exit (-1)
208     else:
209         print "'%s' is neither a valid file nor a yaml/json content" % content
210         exit(-1)
211     return payload
212
213 def _get_item_uuid(item, item_name_id, tenant=None):
214     if tenant:
215         URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, tenant, item)
216     else:
217         URLrequest = "http://%s:%s/openmano/%s" %(mano_host, mano_port, item)
218     mano_response = requests.get(URLrequest)
219     logger.debug("openmano response: %s", mano_response.text )
220     content = mano_response.json()
221     #print content
222     found = 0
223     for i in content[item]:
224         if i["uuid"] == item_name_id:
225             return item_name_id
226         if i["name"] == item_name_id:
227             uuid = i["uuid"]
228             found += 1
229         if item_name_id.startswith("osm_id=") and i.get("osm_id") == item_name_id[7:]:
230             uuid = i["uuid"]
231             found += 1
232     if found == 0:
233         raise OpenmanoCLIError("No %s found with name/uuid '%s'" %(item[:-1], item_name_id))
234     elif found > 1:
235         raise OpenmanoCLIError("%d %s found with name '%s'. uuid must be used" %(found, item, item_name_id))
236     return uuid
237
238 # def check_valid_uuid(uuid):
239 #     id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
240 #     try:
241 #         js_v(uuid, id_schema)
242 #         return True
243 #     except js_e.ValidationError:
244 #         return False
245     
246 def _get_tenant(tenant_name_id = None):
247     if not tenant_name_id:
248         tenant_name_id = mano_tenant
249         if not mano_tenant:
250             raise OpenmanoCLIError("'OPENMANO_TENANT' environment variable is not set")
251     return _get_item_uuid("tenants", tenant_name_id)
252
253 def _get_datacenter(datacenter_name_id = None, tenant = "any"):
254     if not datacenter_name_id:
255         datacenter_name_id = mano_datacenter
256         if not datacenter_name_id:
257             raise OpenmanoCLIError("neither 'OPENMANO_DATACENTER' environment variable is set nor --datacenter option is used")
258     return _get_item_uuid("datacenters", datacenter_name_id, tenant)
259
260 def vnf_create(args):
261     #print "vnf-create",args
262     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
263     tenant = _get_tenant()
264     myvnf = _load_file_or_yaml(args.file)
265     api_version = ""
266     if "vnfd:vnfd-catalog" in myvnf or "vnfd-catalog" in myvnf:
267         api_version = "/v3"
268         token = "vnfd"
269         vnfd_catalog = myvnf.get("vnfd:vnfd-catalog")
270         if not vnfd_catalog:
271             vnfd_catalog = myvnf.get("vnfd-catalog")
272         vnfds = vnfd_catalog.get("vnfd:vnfd")
273         if not vnfds:
274             vnfds = vnfd_catalog.get("vnfd")
275         vnfd = vnfds[0]
276         vdu_list = vnfd.get("vdu")
277
278     else:  # old API
279         api_version = ""
280         token = "vnfs"
281         vnfd = myvnf['vnf']
282         vdu_list = vnfd.get("VNFC")
283
284     if args.name or args.description or args.image_path or args.image_name or args.image_checksum:
285         # TODO, change this for API v3
286         # print args.name
287         try:
288             if args.name:
289                 vnfd['name'] = args.name
290             if args.description:
291                 vnfd['description'] = args.description
292             if vdu_list:
293                 if args.image_path:
294                     index = 0
295                     for image_path_ in args.image_path.split(","):
296                         # print "image-path", image_path_
297                         if api_version == "/v3":
298                             if vdu_list[index].get("image"):
299                                 vdu_list[index]['image'] = image_path_
300                                 if "image-checksum" in vdu_list[index]:
301                                     del vdu_list[index]["image-checksum"]
302                             else:  # image name in volumes
303                                 vdu_list[index]["volumes"][0]["image"] = image_path_
304                                 if "image-checksum" in vdu_list[index]["volumes"][0]:
305                                     del vdu_list[index]["volumes"][0]["image-checksum"]
306                         else:
307                             vdu_list[index]['VNFC image'] = image_path_
308                             if "image name" in vdu_list[index]:
309                                 del vdu_list[index]["image name"]
310                             if "image checksum" in vdu_list[index]:
311                                 del vdu_list[index]["image checksum"]
312                         index += 1
313                 if args.image_name:  # image name precedes if both are supplied
314                     index = 0
315                     for image_name_ in args.image_name.split(","):
316                         if api_version == "/v3":
317                             if vdu_list[index].get("image"):
318                                 vdu_list[index]['image'] = image_name_
319                                 if "image-checksum" in vdu_list[index]:
320                                     del vdu_list[index]["image-checksum"]
321                                 if vdu_list[index].get("alternative-images"):
322                                     for a_image in vdu_list[index]["alternative-images"]:
323                                         a_image['image'] = image_name_
324                                         if "image-checksum" in a_image:
325                                             del a_image["image-checksum"]
326                             else:  # image name in volumes
327                                 vdu_list[index]["volumes"][0]["image"] = image_name_
328                                 if "image-checksum" in vdu_list[index]["volumes"][0]:
329                                     del vdu_list[index]["volumes"][0]["image-checksum"]
330                         else:
331                             vdu_list[index]['image name'] = image_name_
332                             if "VNFC image" in vdu_list[index]:
333                                 del vdu_list[index]["VNFC image"]
334                         index += 1
335                 if args.image_checksum:
336                     index = 0
337                     for image_checksum_ in args.image_checksum.split(","):
338                         if api_version == "/v3":
339                             if vdu_list[index].get("image"):
340                                 vdu_list[index]['image-checksum'] = image_checksum_
341                                 if vdu_list[index].get("alternative-images"):
342                                     for a_image in vdu_list[index]["alternative-images"]:
343                                         a_image['image-checksum'] = image_checksum_
344                             else:  # image name in volumes
345                                 vdu_list[index]["volumes"][0]["image-checksum"] = image_checksum_
346                         else:
347                             vdu_list[index]['image checksum'] = image_checksum_
348                         index += 1
349         except (KeyError, TypeError), e:
350             if str(e) == 'vnf':           error_pos= "missing field 'vnf'"
351             elif str(e) == 'name':        error_pos= "missing field  'vnf':'name'"
352             elif str(e) == 'description': error_pos= "missing field  'vnf':'description'"
353             elif str(e) == 'VNFC':        error_pos= "missing field  'vnf':'VNFC'"
354             elif str(e) == str(index):    error_pos= "field  'vnf':'VNFC' must be an array"
355             elif str(e) == 'VNFC image':  error_pos= "missing field 'vnf':'VNFC'['VNFC image']"
356             elif str(e) == 'image name':  error_pos= "missing field 'vnf':'VNFC'['image name']"
357             elif str(e) == 'image checksum':  error_pos= "missing field 'vnf':'VNFC'['image checksum']"
358             else:                       error_pos="wrong format"
359             print "Wrong VNF descriptor: " + error_pos
360             return -1 
361     payload_req = json.dumps(myvnf)
362         
363     #print payload_req
364         
365     URLrequest = "http://{}:{}/openmano{}/{}/{token}".format(mano_host, mano_port, api_version, tenant, token=token)
366     logger.debug("openmano request: %s", payload_req)
367     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
368     logger.debug("openmano response: %s", mano_response.text )
369
370     return _print_verbose(mano_response, args.verbose)
371
372 def vnf_list(args):
373     #print "vnf-list",args
374     if args.all:
375         tenant = "any"
376     else:
377         tenant = _get_tenant()
378     if args.name:
379         toshow = _get_item_uuid("vnfs", args.name, tenant)
380         URLrequest = "http://%s:%s/openmano/%s/vnfs/%s" %(mano_host, mano_port, tenant, toshow)
381     else:
382         URLrequest = "http://%s:%s/openmano/%s/vnfs" %(mano_host, mano_port, tenant)
383     mano_response = requests.get(URLrequest)
384     logger.debug("openmano response: %s", mano_response.text )
385     content = mano_response.json()
386     # print json.dumps(content, indent=4)
387     if args.verbose==None:
388         args.verbose=0
389     result = 0 if mano_response.status_code==200 else mano_response.status_code
390     if mano_response.status_code == 200:
391         if not args.name:
392             if args.verbose >= 3:
393                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
394                 return result
395             if len(content['vnfs']) == 0:
396                 print "No VNFs were found."
397                 return 404   # HTTP_Not_Found
398             for vnf in content['vnfs']:
399                 myoutput = "{:38} {:20}".format(vnf['uuid'], vnf['name'])
400                 if vnf.get('osm_id') or args.verbose >= 1:
401                     myoutput += " osm_id={:20}".format(vnf.get('osm_id'))
402                 if args.verbose >= 1:
403                     myoutput += " {}".format(vnf['created_at'])
404                 print (myoutput)
405                 if args.verbose >= 2:
406                     print ("  Description: {}".format(vnf['description']))
407                     # print ("  VNF descriptor file: {}".format(vnf['path']))
408         else:
409             if args.verbose:
410                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
411                 return result
412             vnf = content['vnf']
413             print ("{:38} {:20} osm_id={:20} {:20}".format(vnf['uuid'], vnf['name'], vnf.get('osm_id'),
414                                                            vnf['created_at']))
415             print ("  Description: {}".format(vnf['description']))
416             # print "  VNF descriptor file: %s" %vnf['path']
417             print ("  VMs:")
418             for vm in vnf['VNFC']:
419                 print ("    {:20} osm_id={:20} {}".format(vm['name'], vm.get('osm_id'), vm['description']))
420             if len(vnf['nets']) > 0:
421                 print ("  Internal nets:")
422                 for net in vnf['nets']:
423                     print ("    {:20} {}".format(net['name'], net['description']))
424             if len(vnf['external-connections']) > 0:
425                 print ("  External interfaces:")
426                 for interface in vnf['external-connections']:
427                     print ("    {:20} {:20} {:20} {:14}".format(
428                         interface['external_name'], interface['vm_name'],
429                         interface['internal_name'],
430                         interface.get('vpci') if interface.get('vpci') else ""))
431     else:
432         print content['error']['description']
433         if args.verbose:
434             print yaml.safe_dump(content, indent=4, default_flow_style=False)
435     return result
436
437 def vnf_delete(args):
438     #print "vnf-delete",args
439     if args.all:
440         tenant = "any"
441     else:
442         tenant = _get_tenant()
443     todelete = _get_item_uuid("vnfs", args.name, tenant=tenant)
444     if not args.force:
445         r = raw_input("Delete VNF %s (y/N)? " %(todelete))
446         if  not (len(r)>0  and r[0].lower()=="y"):
447             return 0
448     URLrequest = "http://%s:%s/openmano/%s/vnfs/%s" %(mano_host, mano_port, tenant, todelete)
449     mano_response = requests.delete(URLrequest)
450     logger.debug("openmano response: %s", mano_response.text )
451     result = 0 if mano_response.status_code==200 else mano_response.status_code
452     content = mano_response.json()
453     #print json.dumps(content, indent=4)
454     if mano_response.status_code == 200:
455         print content['result']
456     else:
457         print content['error']['description']
458     return result
459
460 def scenario_create(args):
461     # print "scenario-create",args
462     tenant = _get_tenant()
463     headers_req = {'content-type': 'application/yaml'}
464     myscenario = _load_file_or_yaml(args.file)
465     if "nsd:nsd-catalog" in myscenario or "nsd-catalog" in myscenario:
466         api_version = "/v3"
467         token = "nsd"
468         nsd_catalog = myscenario.get("nsd:nsd-catalog")
469         if not nsd_catalog:
470             nsd_catalog = myscenario.get("nsd-catalog")
471         nsds = nsd_catalog.get("nsd:nsd")
472         if not nsds:
473             nsds = nsd_catalog.get("nsd")
474         nsd = nsds[0]
475     else:  # API<v3
476         api_version = ""
477         token = "scenarios"
478         if "scenario" in myscenario:
479             nsd = myscenario["scenario"]
480         else:
481             nsd = myscenario
482     # TODO modify for API v3
483     if args.name:
484         nsd['name'] = args.name
485     if args.description:
486         nsd['description'] = args.description
487     payload_req = yaml.safe_dump(myscenario, explicit_start=True, indent=4, default_flow_style=False, tags=False,
488                                  encoding='utf-8', allow_unicode=True)
489     
490     # print payload_req
491     URLrequest = "http://{host}:{port}/openmano{api}/{tenant}/{token}".format(
492         host=mano_host, port=mano_port, api=api_version, tenant=tenant, token=token)
493     logger.debug("openmano request: %s", payload_req)
494     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
495     logger.debug("openmano response: %s", mano_response.text )
496     return _print_verbose(mano_response, args.verbose)
497
498 def scenario_list(args):
499     #print "scenario-list",args
500     if args.all:
501         tenant = "any"
502     else:
503         tenant = _get_tenant()
504     if args.name:
505         toshow = _get_item_uuid("scenarios", args.name, tenant)
506         URLrequest = "http://%s:%s/openmano/%s/scenarios/%s" %(mano_host, mano_port, tenant, toshow)
507     else:
508         URLrequest = "http://%s:%s/openmano/%s/scenarios" %(mano_host, mano_port, tenant)
509     mano_response = requests.get(URLrequest)
510     logger.debug("openmano response: %s", mano_response.text )
511     content = mano_response.json()
512     #print json.dumps(content, indent=4)
513     if args.verbose==None:
514         args.verbose=0
515
516     result = 0 if mano_response.status_code==200 else mano_response.status_code
517     if mano_response.status_code == 200:
518         if not args.name:
519             if args.verbose >= 3:
520                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
521                 return result
522             if len(content['scenarios']) == 0:
523                 print "No scenarios were found."
524                 return 404 #HTTP_Not_Found
525             for scenario in content['scenarios']:
526                 myoutput = "{:38} {:20}".format(scenario['uuid'], scenario['name'])
527                 if scenario.get('osm_id') or args.verbose >= 1:
528                     myoutput += " osm_id={:20}".format(scenario.get('osm_id'))
529                 if args.verbose >= 1:
530                     myoutput += " {}".format(scenario['created_at'])
531                 print (myoutput)
532                 if args.verbose >=2:
533                     print ("  Description: {}".format(scenario['description']))
534         else:
535             if args.verbose:
536                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
537                 return result
538             scenario = content['scenario']
539             print ("{:38} {:20} osm_id={:20} {:20}".format(scenario['uuid'], scenario['name'], scenario.get('osm_id'),
540                                                            scenario['created_at']))
541             print ("  Description: {}".format(scenario['description']))
542             print ("  VNFs:")
543             for vnf in scenario['vnfs']:
544                 print ("    {:38} {:20} vnf_index={} {}".format(vnf['vnf_id'], vnf['name'], vnf.get("member_vnf_index"),
545                                                                 vnf['description']))
546             if len(scenario['nets']) > 0:
547                 print ("  nets:")
548                 for net in scenario['nets']:
549                     description = net['description']
550                     if not description:   # if description does not exist, description is "-". Valid for external and internal nets.
551                         description = '-'
552                     vim_id = ""
553                     if net.get('vim_id'):
554                         vim_id = " vim_id=" + net["vim_id"]
555                     external = ""
556                     if net["external"]:
557                         external = " external"
558                     print ("    {:20} {:38} {:30}{}{}".format(net['name'], net['uuid'], description, vim_id, external))
559     else:
560         print (content['error']['description'])
561         if args.verbose:
562             print yaml.safe_dump(content, indent=4, default_flow_style=False)
563     return result
564
565 def scenario_delete(args):
566     #print "scenario-delete",args
567     if args.all:
568         tenant = "any"
569     else:
570         tenant = _get_tenant()
571     todelete = _get_item_uuid("scenarios", args.name, tenant=tenant)
572     if not args.force:
573         r = raw_input("Delete scenario %s (y/N)? " %(args.name))
574         if  not (len(r)>0  and r[0].lower()=="y"):
575             return 0
576     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s" %(mano_host, mano_port, tenant, todelete)
577     mano_response = requests.delete(URLrequest)
578     logger.debug("openmano response: %s", mano_response.text )
579     result = 0 if mano_response.status_code==200 else mano_response.status_code
580     content = mano_response.json()
581     #print json.dumps(content, indent=4)
582     if mano_response.status_code == 200:
583         print content['result']
584     else:
585         print content['error']['description']
586     return result
587
588 def scenario_deploy(args):
589     print "This command is deprecated, use 'openmano instance-scenario-create --scenario %s --name %s' instead!!!" % (args.scenario, args.name)
590     print
591     args.file = None
592     args.netmap_use = None
593     args.netmap_create = None
594     args.keypair = None
595     args.keypair_auto = None
596     return instance_create(args)
597
598 #     #print "scenario-deploy",args
599 #     headers_req = {'content-type': 'application/json'}
600 #     action = {}
601 #     actionCmd="start"
602 #     if args.nostart:
603 #         actionCmd="reserve"
604 #     action[actionCmd] = {}
605 #     action[actionCmd]["instance_name"] = args.name
606 #     if args.datacenter != None:
607 #         action[actionCmd]["datacenter"] = args.datacenter
608 #     elif mano_datacenter != None:
609 #         action[actionCmd]["datacenter"] = mano_datacenter
610 #         
611 #     if args.description:
612 #         action[actionCmd]["description"] = args.description
613 #     payload_req = json.dumps(action, indent=4)
614 #     #print payload_req
615
616 #     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, mano_tenant, args.scenario)
617 #     logger.debug("openmano request: %s", payload_req)
618 #     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
619 #     logger.debug("openmano response: %s", mano_response.text )
620 #     if args.verbose==None:
621 #         args.verbose=0
622 #     
623 #     result = 0 if mano_response.status_code==200 else mano_response.status_code
624 #     content = mano_response.json()
625 #     #print json.dumps(content, indent=4)
626 #     if args.verbose >= 3:
627 #         print yaml.safe_dump(content, indent=4, default_flow_style=False)
628 #         return result
629
630 #     if mano_response.status_code == 200:
631 #         myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
632 #         if args.verbose >=1:
633 #             myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
634 #         if args.verbose >=2:
635 #             myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
636 #         print myoutput
637 #         print ""
638 #         print "To check the status, run the following command:"
639 #         print "openmano instance-scenario-list <instance_id>"
640 #     else:
641 #         print content['error']['description']
642 #     return result
643
644 def scenario_verify(args):
645     #print "scenario-verify",args
646     tenant = _get_tenant()
647     headers_req = {'content-type': 'application/json'}
648     action = {}
649     action["verify"] = {}
650     action["verify"]["instance_name"] = "scen-verify-return5"
651     payload_req = json.dumps(action, indent=4)
652     #print payload_req
653
654     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, tenant, args.scenario)
655     logger.debug("openmano request: %s", payload_req)
656     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
657     logger.debug("openmano response: %s", mano_response.text )
658     
659     result = 0 if mano_response.status_code==200 else mano_response.status_code
660     content = mano_response.json()
661     #print json.dumps(content, indent=4)
662     if mano_response.status_code == 200:
663         print content['result']
664     else:
665         print content['error']['description']
666     return result
667
668 def instance_create(args):
669     tenant = _get_tenant()
670     headers_req = {'content-type': 'application/yaml'}
671     myInstance={"instance": {}, "schema_version": "0.1"}
672     if args.file:
673         instance_dict = _load_file_or_yaml(args.file)
674         if "instance" not in instance_dict:
675             myInstance = {"instance": instance_dict, "schema_version": "0.1"}
676         else:
677             myInstance = instance_dict
678     if args.name:
679         myInstance["instance"]['name'] = args.name
680     if args.description:
681         myInstance["instance"]['description'] = args.description
682     if args.nostart:
683         myInstance["instance"]['action'] = "reserve"
684     #datacenter
685     datacenter = myInstance["instance"].get("datacenter")
686     if args.datacenter != None:
687         datacenter = args.datacenter
688     myInstance["instance"]["datacenter"] = _get_datacenter(datacenter, tenant)
689     #scenario
690     scenario = myInstance["instance"].get("scenario")
691     if args.scenario != None:
692         scenario = args.scenario
693     if not scenario:
694         print "you must provide a scenario in the file descriptor or with --scenario"
695         return -1
696     if isinstance(scenario, str):
697         myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
698     if args.netmap_use:
699         if "networks" not in myInstance["instance"]:
700             myInstance["instance"]["networks"] = {}
701         for net in args.netmap_use:
702             net_comma_list = net.split(",")
703             for net_comma in net_comma_list:
704                 net_tuple = net_comma.split("=")
705                 if len(net_tuple) != 2:
706                     print "error at netmap-use. Expected net-scenario=net-datacenter. (%s)?" % net_comma
707                     return
708                 net_scenario   = net_tuple[0].strip()
709                 net_datacenter = net_tuple[1].strip()
710                 if net_scenario not in myInstance["instance"]["networks"]:
711                     myInstance["instance"]["networks"][net_scenario] = {} 
712                 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
713                     myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
714                 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-use"] = net_datacenter
715     if args.netmap_create:
716         if "networks" not in myInstance["instance"]:
717             myInstance["instance"]["networks"] = {}
718         for net in args.netmap_create:
719             net_comma_list = net.split(",")
720             for net_comma in net_comma_list:
721                 net_tuple = net_comma.split("=")
722                 if len(net_tuple) == 1:
723                     net_scenario   = net_tuple[0].strip()
724                     net_datacenter = None
725                 elif len(net_tuple) == 2:
726                     net_scenario   = net_tuple[0].strip()
727                     net_datacenter = net_tuple[1].strip()
728                 else:
729                     print "error at netmap-create. Expected net-scenario=net-datacenter or net-scenario. (%s)?" % net_comma
730                     return
731                 if net_scenario not in myInstance["instance"]["networks"]:
732                     myInstance["instance"]["networks"][net_scenario] = {} 
733                 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
734                     myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
735                 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-create"] = net_datacenter
736     if args.keypair:
737         if "cloud-config" not in myInstance["instance"]:
738             myInstance["instance"]["cloud-config"] = {}
739         cloud_config = myInstance["instance"]["cloud-config"]
740         for key in args.keypair:
741             index = key.find(":")
742             if index<0:
743                 if "key-pairs" not in cloud_config:
744                     cloud_config["key-pairs"] = []
745                 cloud_config["key-pairs"].append(key)
746             else:
747                 user = key[:index]
748                 key_ = key[index+1:]
749                 key_list = key_.split(",")
750                 if "users" not in cloud_config:
751                     cloud_config["users"] = []
752                 cloud_config["users"].append({"name": user, "key-pairs": key_list  })
753     if args.keypair_auto:
754         try:
755             keys=[]
756             home = os.getenv("HOME")
757             user = os.getenv("USER")
758             files = os.listdir(home+'/.ssh')
759             for file in files:
760                 if file[-4:] == ".pub":
761                     with open(home+'/.ssh/'+file, 'r') as f:
762                         keys.append(f.read())
763             if not keys:
764                 print "Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh')
765                 return 1
766         except Exception as e:
767             print "Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e))
768             return 1
769         
770         if "cloud-config" not in myInstance["instance"]:
771             myInstance["instance"]["cloud-config"] = {}
772         cloud_config = myInstance["instance"]["cloud-config"]
773         if "key-pairs" not in cloud_config:
774             cloud_config["key-pairs"] = []
775         if user:
776             if "users" not in cloud_config:
777                 cloud_config["users"] = []
778             cloud_config["users"].append({"name": user, "key-pairs": keys })                    
779                         
780     payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
781     logger.debug("openmano request: %s", payload_req)
782     URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
783     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
784     logger.debug("openmano response: %s", mano_response.text )
785     if args.verbose==None:
786         args.verbose=0
787     
788     result = 0 if mano_response.status_code==200 else mano_response.status_code
789     content = mano_response.json()
790     #print json.dumps(content, indent=4)
791     if args.verbose >= 3:
792         print yaml.safe_dump(content, indent=4, default_flow_style=False)
793         return result
794
795     if mano_response.status_code == 200:
796         myoutput = "{:38} {:20}".format(content['uuid'], content['name'])
797         if args.verbose >=1:
798             myoutput = "{} {:20}".format(myoutput, content['created_at'])
799         if args.verbose >=2:
800             myoutput = "{} {:30}".format(myoutput, content['description'])
801         print myoutput
802     else:
803         print content['error']['description']
804     return result
805
806 def instance_scenario_list(args):
807     #print "instance-scenario-list",args
808     if args.all:
809         tenant = "any"
810     else:
811         tenant = _get_tenant()
812     if args.name:
813         toshow = _get_item_uuid("instances", args.name, tenant)
814         URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, toshow)
815     else:
816         URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
817     mano_response = requests.get(URLrequest)
818     logger.debug("openmano response: %s", mano_response.text )
819     content = mano_response.json()
820     #print json.dumps(content, indent=4)
821     if args.verbose==None:
822         args.verbose=0
823
824     result = 0 if mano_response.status_code==200 else mano_response.status_code
825     if mano_response.status_code == 200:
826         if not args.name:
827             if args.verbose >= 3:
828                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
829                 return result
830             if len(content['instances']) == 0:
831                 print "No scenario instances were found."
832                 return result
833             for instance in content['instances']:
834                 myoutput = "{:38} {:20}".format(instance['uuid'], instance['name'])
835                 if args.verbose >=1:
836                     myoutput = "{} {:20}".format(myoutput, instance['created_at'])
837                 print myoutput
838                 if args.verbose >=2:
839                     print "Description: %s" %instance['description']
840         else:
841             if args.verbose:
842                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
843                 return result
844             instance = content
845             print ("{:38} {:20} {:20}".format(instance['uuid'],instance['name'],instance['created_at']))
846             print ("Description: %s" %instance['description'])
847             print ("Template scenario id: {}".format(instance['scenario_id']))
848             print ("Template scenario name: {}".format(instance['scenario_name']))
849             print ("---------------------------------------")
850             print ("VNF instances: {}".format(len(instance['vnfs'])))
851             for vnf in instance['vnfs']:
852                 #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))
853                 print ("    {:38} {:20} Template vnf id: {:38}".format(vnf['uuid'], vnf['vnf_name'], vnf['vnf_id']))
854             if len(instance['nets'])>0:
855                 print "---------------------------------------"
856                 print "Internal nets:"
857                 for net in instance['nets']:
858                     if net['created']:
859                         print ("    {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
860                 print "---------------------------------------"
861                 print "External nets:"
862                 for net in instance['nets']:
863                     if not net['created']:
864                         print ("    {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
865             print ("---------------------------------------")
866             print ("VM instances:")
867             for vnf in instance['vnfs']:
868                 for vm in vnf['vms']:
869                     print ("    {:38} {:20} {:20} {:12} VIM ID: {}".format(vm['uuid'], vnf['vnf_name'], vm['name'],
870                                                                            vm['status'], vm['vim_vm_id']))
871     else:
872         print content['error']['description']
873         if args.verbose:
874             print yaml.safe_dump(content, indent=4, default_flow_style=False)
875     return result
876
877 def instance_scenario_status(args):
878     print "instance-scenario-status"
879     return 0
880
881 def instance_scenario_delete(args):
882     if args.all:
883         tenant = "any"
884     else:
885         tenant = _get_tenant()
886     todelete = _get_item_uuid("instances", args.name, tenant=tenant)
887     #print "instance-scenario-delete",args
888     if not args.force:
889         r = raw_input("Delete scenario instance %s (y/N)? " %(args.name))
890         if  not (len(r)>0  and r[0].lower()=="y"):
891             return
892     URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, todelete)
893     mano_response = requests.delete(URLrequest)
894     logger.debug("openmano response: %s", mano_response.text )
895     result = 0 if mano_response.status_code==200 else mano_response.status_code
896     content = mano_response.json()
897     #print json.dumps(content, indent=4)
898     if mano_response.status_code == 200:
899         print content['result']
900     else:
901         print content['error']['description']
902     return result
903
904 def get_action(args):
905     if not args.all:
906         tenant = _get_tenant()
907     else:
908         tenant = "any"
909     if not args.instance:
910         instance_id = "any"
911     else:
912         instance_id =args.instance
913     action_id = ""
914     if args.id:
915         action_id = "/" + args.id
916     URLrequest = "http://{}:{}/openmano/{}/instances/{}/action{}".format(mano_host, mano_port, tenant, instance_id,
917                                                                          action_id)
918     mano_response = requests.get(URLrequest)
919     logger.debug("openmano response: %s", mano_response.text )
920     if args.verbose == None:
921         args.verbose = 0
922     if args.id != None:
923         args.verbose += 1
924     return _print_verbose(mano_response, args.verbose)
925
926 def instance_scenario_action(args):
927     #print "instance-scenario-action", args
928     tenant = _get_tenant()
929     toact = _get_item_uuid("instances", args.name, tenant=tenant)
930     action={}
931     action[ args.action ] = yaml.safe_load(args.param)
932     if args.vnf:
933         action["vnfs"] = args.vnf
934     if args.vm:
935         action["vms"] = args.vm
936     
937     headers_req = {'content-type': 'application/json'}
938     payload_req = json.dumps(action, indent=4)
939     URLrequest = "http://%s:%s/openmano/%s/instances/%s/action" %(mano_host, mano_port, tenant, toact)
940     logger.debug("openmano request: %s", payload_req)
941     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
942     logger.debug("openmano response: %s", mano_response.text )
943     result = 0 if mano_response.status_code==200 else mano_response.status_code
944     content = mano_response.json()
945     # print json.dumps(content, indent=4)
946     if mano_response.status_code == 200:
947         if args.verbose:
948             print yaml.safe_dump(content, indent=4, default_flow_style=False)
949             return result
950         if "instance_action_id" in content:
951             print("instance_action_id={}".format(content["instance_action_id"]))
952         else:
953             for uuid,c in content.iteritems():
954                 print ("{:38} {:20} {:20}".format(uuid, c.get('name'), c.get('description')))
955     else:
956         print content['error']['description']
957     return result
958
959
960 def instance_vnf_list(args):
961     print "instance-vnf-list"
962     return 0
963
964 def instance_vnf_status(args):
965     print "instance-vnf-status"
966     return 0
967
968 def tenant_create(args):
969     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
970     tenant_dict={"name": args.name}
971     if args.description!=None:
972         tenant_dict["description"] = args.description 
973     payload_req = json.dumps( {"tenant": tenant_dict })
974     
975     #print payload_req
976         
977     URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
978     logger.debug("openmano request: %s", payload_req)
979     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
980     logger.debug("openmano response: %s", mano_response.text )
981     return _print_verbose(mano_response, args.verbose)
982
983 def tenant_list(args):
984     #print "tenant-list",args
985     if args.name:
986         toshow = _get_item_uuid("tenants", args.name)
987         URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, toshow)
988     else:
989         URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
990     mano_response = requests.get(URLrequest)
991     logger.debug("openmano response: %s", mano_response.text )
992     if args.verbose==None:
993         args.verbose=0
994     if args.name!=None:
995         args.verbose += 1
996     return _print_verbose(mano_response, args.verbose)
997
998 def tenant_delete(args):
999     #print "tenant-delete",args
1000     todelete = _get_item_uuid("tenants", args.name)
1001     if not args.force:
1002         r = raw_input("Delete tenant %s (y/N)? " %(args.name))
1003         if  not (len(r)>0  and r[0].lower()=="y"):
1004             return 0
1005     URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, todelete)
1006     mano_response = requests.delete(URLrequest)
1007     logger.debug("openmano response: %s", mano_response.text )
1008     result = 0 if mano_response.status_code==200 else mano_response.status_code
1009     content = mano_response.json()
1010     #print json.dumps(content, indent=4)
1011     if mano_response.status_code == 200:
1012         print content['result']
1013     else:
1014         print content['error']['description']
1015     return result
1016
1017 def datacenter_attach(args):
1018     tenant = _get_tenant()
1019     datacenter = _get_datacenter(args.name)
1020     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1021     
1022     datacenter_dict={}
1023     if args.vim_tenant_id != None:
1024         datacenter_dict['vim_tenant'] = args.vim_tenant_id
1025     if args.vim_tenant_name != None:
1026         datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
1027     if args.user != None:
1028         datacenter_dict['vim_username'] = args.user
1029     if args.password != None:
1030         datacenter_dict['vim_password'] = args.password
1031     if args.config!=None:
1032         datacenter_dict["config"] = _load_file_or_yaml(args.config)
1033
1034     payload_req = json.dumps( {"datacenter": datacenter_dict })
1035
1036     #print payload_req
1037         
1038     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
1039     logger.debug("openmano request: %s", payload_req)
1040     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1041     logger.debug("openmano response: %s", mano_response.text )
1042     result = _print_verbose(mano_response, args.verbose)
1043     #provide addional information if error
1044     if mano_response.status_code != 200:
1045         content = mano_response.json()
1046         if "already in use for  'name'" in content['error']['description'] and \
1047                 "to database vim_tenants table" in content['error']['description']:
1048             print "Try to specify a different name with --vim-tenant-name"
1049     return result
1050
1051
1052 def datacenter_edit_vim_tenant(args):
1053     tenant = _get_tenant()
1054     datacenter = _get_datacenter(args.name)
1055     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1056
1057     if not (args.vim_tenant_id or args.vim_tenant_name or args.user or args.password or args.config):
1058         raise OpenmanoCLIError("Error. At least one parameter must be updated.")
1059
1060     datacenter_dict = {}
1061     if args.vim_tenant_id != None:
1062         datacenter_dict['vim_tenant'] = args.vim_tenant_id
1063     if args.vim_tenant_name != None:
1064         datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
1065     if args.user != None:
1066         datacenter_dict['vim_username'] = args.user
1067     if args.password != None:
1068         datacenter_dict['vim_password'] = args.password
1069     if args.config != None:
1070         datacenter_dict["config"] = _load_file_or_yaml(args.config)
1071     payload_req = json.dumps({"datacenter": datacenter_dict})
1072
1073     # print payload_req
1074
1075     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" % (mano_host, mano_port, tenant, datacenter)
1076     logger.debug("openmano request: %s", payload_req)
1077     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1078     logger.debug("openmano response: %s", mano_response.text)
1079     result = _print_verbose(mano_response, args.verbose)
1080
1081     return result
1082
1083 def datacenter_detach(args):
1084     if args.all:
1085         tenant = "any"
1086     else:
1087         tenant = _get_tenant()
1088     datacenter = _get_datacenter(args.name, tenant)
1089     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1090     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
1091     mano_response = requests.delete(URLrequest, headers=headers_req)
1092     logger.debug("openmano response: %s", mano_response.text )
1093     content = mano_response.json()
1094     #print json.dumps(content, indent=4)
1095     result = 0 if mano_response.status_code==200 else mano_response.status_code
1096     if mano_response.status_code == 200:
1097         print content['result']
1098     else:
1099         print content['error']['description']
1100     return result
1101
1102 def datacenter_create(args):
1103     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1104     datacenter_dict={"name": args.name, "vim_url": args.url}
1105     if args.description!=None:
1106         datacenter_dict["description"] = args.description 
1107     if args.type!=None:
1108         datacenter_dict["type"] = args.type 
1109     if args.url!=None:
1110         datacenter_dict["vim_url_admin"] = args.url_admin 
1111     if args.config!=None:
1112         datacenter_dict["config"] = _load_file_or_yaml(args.config)
1113     if args.sdn_controller!=None:
1114         tenant = _get_tenant()
1115         sdn_controller = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
1116         if not 'config' in datacenter_dict:
1117             datacenter_dict['config'] = {}
1118         datacenter_dict['config']['sdn-controller'] = sdn_controller
1119     payload_req = json.dumps( {"datacenter": datacenter_dict })
1120     
1121     #print payload_req
1122         
1123     URLrequest = "http://%s:%s/openmano/datacenters" %(mano_host, mano_port)
1124     logger.debug("openmano request: %s", payload_req)
1125     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1126     logger.debug("openmano response: %s", mano_response.text )
1127     return _print_verbose(mano_response, args.verbose)
1128
1129 def datacenter_delete(args):
1130     #print "datacenter-delete",args
1131     todelete = _get_item_uuid("datacenters", args.name, "any")
1132     if not args.force:
1133         r = raw_input("Delete datacenter %s (y/N)? " %(args.name))
1134         if  not (len(r)>0  and r[0].lower()=="y"):
1135             return 0
1136     URLrequest = "http://%s:%s/openmano/datacenters/%s" %(mano_host, mano_port, todelete)
1137     mano_response = requests.delete(URLrequest)
1138     logger.debug("openmano response: %s", mano_response.text )
1139     result = 0 if mano_response.status_code==200 else mano_response.status_code
1140     content = mano_response.json()
1141     #print json.dumps(content, indent=4)
1142     if mano_response.status_code == 200:
1143         print content['result']
1144     else:
1145         print content['error']['description']
1146     return result
1147
1148
1149 def datacenter_list(args):
1150     #print "datacenter-list",args
1151     tenant='any' if args.all else _get_tenant()
1152     
1153     if args.name:
1154         toshow = _get_item_uuid("datacenters", args.name, tenant) 
1155         URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, toshow)
1156     else:
1157         URLrequest = "http://%s:%s/openmano/%s/datacenters" %(mano_host, mano_port, tenant)
1158     mano_response = requests.get(URLrequest)
1159     logger.debug("openmano response: %s", mano_response.text )
1160     if args.verbose==None:
1161         args.verbose=0
1162     if args.name!=None:
1163         args.verbose += 1
1164     return _print_verbose(mano_response, args.verbose)
1165
1166
1167 def datacenter_sdn_port_mapping_set(args):
1168     tenant = _get_tenant()
1169     datacenter = _get_datacenter(args.name, tenant)
1170     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1171
1172     if not args.file:
1173         raise OpenmanoCLIError(
1174             "No yaml/json has been provided specifying the SDN port mapping")
1175     sdn_port_mapping = _load_file_or_yaml(args.file)
1176     payload_req = json.dumps({"sdn_port_mapping": sdn_port_mapping})
1177
1178     # read
1179     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1180     mano_response = requests.get(URLrequest)
1181     logger.debug("openmano response: %s", mano_response.text)
1182     port_mapping = mano_response.json()
1183     if mano_response.status_code != 200:
1184         str(mano_response.json())
1185         raise OpenmanoCLIError("openmano client error: {}".format(port_mapping['error']['description']))
1186     if len(port_mapping["sdn_port_mapping"]["ports_mapping"]) > 0:
1187         if not args.force:
1188             r = raw_input("Datacenter %s already contains a port mapping. Overwrite? (y/N)? " % (datacenter))
1189             if not (len(r) > 0 and r[0].lower() == "y"):
1190                 return 0
1191
1192         # clear
1193         URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1194         mano_response = requests.delete(URLrequest)
1195         logger.debug("openmano response: %s", mano_response.text)
1196         if mano_response.status_code != 200:
1197             return _print_verbose(mano_response, args.verbose)
1198
1199     # set
1200     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1201     logger.debug("openmano request: %s", payload_req)
1202     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1203     logger.debug("openmano response: %s", mano_response.text)
1204     return _print_verbose(mano_response, args.verbose)
1205
1206
1207 def datacenter_sdn_port_mapping_list(args):
1208     tenant = _get_tenant()
1209     datacenter = _get_datacenter(args.name, tenant)
1210
1211     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1212     mano_response = requests.get(URLrequest)
1213     logger.debug("openmano response: %s", mano_response.text)
1214
1215     return _print_verbose(mano_response, 4)
1216
1217
1218 def datacenter_sdn_port_mapping_clear(args):
1219     tenant = _get_tenant()
1220     datacenter = _get_datacenter(args.name, tenant)
1221
1222     if not args.force:
1223         r = raw_input("Clean SDN port mapping for datacenter %s (y/N)? " %(datacenter))
1224         if not (len(r) > 0 and r[0].lower() == "y"):
1225             return 0
1226
1227     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1228     mano_response = requests.delete(URLrequest)
1229     logger.debug("openmano response: %s", mano_response.text)
1230
1231     return _print_verbose(mano_response, args.verbose)
1232
1233
1234 def sdn_controller_create(args):
1235     tenant = _get_tenant()
1236     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1237
1238     error_msg=[]
1239     if not args.ip: error_msg.append("'ip'")
1240     if not args.port: error_msg.append("'port'")
1241     if not args.dpid: error_msg.append("'dpid'")
1242     if not args.type: error_msg.append("'type'")
1243     if error_msg:
1244         raise OpenmanoCLIError("The following arguments are required: " + ",".join(error_msg))
1245
1246     controller_dict = {}
1247     controller_dict['name'] = args.name
1248     controller_dict['ip'] = args.ip
1249     controller_dict['port'] = int(args.port)
1250     controller_dict['dpid'] = args.dpid
1251     controller_dict['type'] = args.type
1252     if args.description != None:
1253         controller_dict['description'] = args.description
1254     if args.user != None:
1255         controller_dict['user'] = args.user
1256     if args.password != None:
1257         controller_dict['password'] = args.password
1258
1259     payload_req = json.dumps({"sdn_controller": controller_dict})
1260
1261     # print payload_req
1262
1263     URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" % (mano_host, mano_port, tenant)
1264     logger.debug("openmano request: %s", payload_req)
1265     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1266     logger.debug("openmano response: %s", mano_response.text)
1267     result = _print_verbose(mano_response, args.verbose)
1268     return result
1269
1270
1271 def sdn_controller_edit(args):
1272     tenant = _get_tenant()
1273     controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
1274     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1275
1276     controller_dict = {}
1277     if args.new_name:
1278         controller_dict['name'] = args.new_name
1279     if args.ip:
1280         controller_dict['ip'] = args.ip
1281     if args.port:
1282         controller_dict['port'] = int(args.port)
1283     if args.dpid:
1284         controller_dict['dpid'] = args.dpid
1285     if args.type:
1286         controller_dict['type'] = args.type
1287     if args.description:
1288         controller_dict['description'] = args.description
1289     if args.user:
1290         controller_dict['user'] = args.user
1291     if args.password:
1292         controller_dict['password'] = args.password
1293
1294     if not controller_dict:
1295         raise OpenmanoCLIError("At least one parameter must be edited")
1296
1297     if not args.force:
1298         r = raw_input("Update SDN controller {} (y/N)? ".format(args.name))
1299         if not (len(r) > 0 and r[0].lower() == "y"):
1300             return 0
1301
1302     payload_req = json.dumps({"sdn_controller": controller_dict})
1303     # print payload_req
1304
1305     URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
1306     logger.debug("openmano request: %s", payload_req)
1307     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1308     logger.debug("openmano response: %s", mano_response.text)
1309     result = _print_verbose(mano_response, args.verbose)
1310     return result
1311
1312
1313 def sdn_controller_list(args):
1314     tenant = _get_tenant()
1315     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1316
1317     if args.name:
1318         toshow = _get_item_uuid("sdn_controllers", args.name, tenant)
1319         URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" %(mano_host, mano_port, tenant, toshow)
1320     else:
1321         URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" %(mano_host, mano_port, tenant)
1322     #print URLrequest
1323     mano_response = requests.get(URLrequest)
1324     logger.debug("openmano response: %s", mano_response.text )
1325     if args.verbose==None:
1326         args.verbose=0
1327     if args.name!=None:
1328         args.verbose += 1
1329
1330     # json.dumps(mano_response.json(), indent=4)
1331     return _print_verbose(mano_response, args.verbose)
1332
1333
1334 def sdn_controller_delete(args):
1335     tenant = _get_tenant()
1336     controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
1337
1338     if not args.force:
1339         r = raw_input("Delete SDN controller %s (y/N)? " % (args.name))
1340         if not (len(r) > 0 and r[0].lower() == "y"):
1341             return 0
1342
1343     URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
1344     mano_response = requests.delete(URLrequest)
1345     logger.debug("openmano response: %s", mano_response.text)
1346     return _print_verbose(mano_response, args.verbose)
1347
1348 def vim_action(args):
1349     #print "datacenter-net-action",args
1350     tenant = _get_tenant()
1351     datacenter = _get_datacenter(args.datacenter, tenant)
1352     if args.verbose==None:
1353         args.verbose=0
1354     if args.action=="list":
1355         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
1356         if args.name!=None:
1357             args.verbose += 1
1358             URLrequest += "/" + args.name
1359         mano_response = requests.get(URLrequest)
1360         logger.debug("openmano response: %s", mano_response.text )
1361         return _print_verbose(mano_response, args.verbose)
1362     elif args.action=="delete":
1363         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss/%s" %(mano_host, mano_port, tenant, datacenter, args.item, args.name)
1364         mano_response = requests.delete(URLrequest)
1365         logger.debug("openmano response: %s", mano_response.text )
1366         result = 0 if mano_response.status_code==200 else mano_response.status_code
1367         content = mano_response.json()
1368         #print json.dumps(content, indent=4)
1369         if mano_response.status_code == 200:
1370             print content['result']
1371         else:
1372             print content['error']['description']
1373         return result
1374     elif args.action=="create":
1375         headers_req = {'content-type': 'application/yaml'}
1376         if args.file:
1377             create_dict = _load_file_or_yaml(args.file)
1378             if args.item not in create_dict:
1379                 create_dict = {args.item: create_dict}
1380         else:
1381             create_dict = {args.item:{}}
1382         if args.name:
1383             create_dict[args.item]['name'] = args.name
1384         #if args.description:
1385         #    create_dict[args.item]['description'] = args.description
1386         if args.item=="network":
1387             if args.bind_net:
1388                 create_dict[args.item]['bind_net'] = args.bind_net
1389             if args.type:
1390                 create_dict[args.item]['type'] = args.type
1391             if args.shared:
1392                 create_dict[args.item]['shared'] = args.shared
1393         if "name" not in create_dict[args.item]:
1394             print "You must provide a name in the descriptor file or with the --name option"
1395             return
1396         payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
1397         logger.debug("openmano request: %s", payload_req)
1398         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
1399         mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
1400         logger.debug("openmano response: %s", mano_response.text )
1401         if args.verbose==None:
1402             args.verbose=0
1403         return _print_verbose(mano_response, args.verbose)
1404
1405
1406 def _get_items(item, item_name_id=None, datacenter=None, tenant=None):
1407     URLrequest = "http://%s:%s/openmano" %(mano_host, mano_port)
1408     if tenant:
1409         URLrequest += "/" + tenant
1410     if datacenter:
1411         URLrequest += "/vim/" + datacenter
1412     if item:
1413         URLrequest += "/" + item +"s"
1414     if item_name_id:
1415         URLrequest += "/" + item_name_id
1416     mano_response = requests.get(URLrequest)
1417     logger.debug("openmano response: %s", mano_response.text )
1418
1419     return mano_response
1420
1421
1422 def vim_net_sdn_attach(args):
1423     #Verify the network exists in the vim
1424     tenant = _get_tenant()
1425     datacenter = _get_datacenter(args.datacenter, tenant)
1426     result = _get_items('network', item_name_id=args.vim_net, datacenter=datacenter, tenant=tenant)
1427     content = yaml.load(result.content)
1428     if 'networks' in content:
1429         raise OpenmanoCLIError('More than one network in the vim named ' + args.vim_net + '. Use uuid instead')
1430     if 'error' in content:
1431         raise OpenmanoCLIError(yaml.safe_dump(content))
1432     network_uuid = content['network']['id']
1433
1434     #Make call to attach the dataplane port to the SND network associated to the vim network
1435     headers_req = {'content-type': 'application/yaml'}
1436     payload_req = {'port': args.port}
1437     if args.vlan:
1438         payload_req['vlan'] = int(args.vlan)
1439     if args.mac:
1440         payload_req['mac'] = args.mac
1441
1442     URLrequest = "http://%s:%s/openmano/%s/vim/%s/network/%s/attach" % (mano_host, mano_port, tenant, datacenter, network_uuid)
1443     logger.debug("openmano request: %s", payload_req)
1444     mano_response = requests.post(URLrequest, headers=headers_req, data=json.dumps(payload_req))
1445     logger.debug("openmano response: %s", mano_response.text)
1446     result = _print_verbose(mano_response, args.verbose)
1447     return result
1448
1449
1450 def vim_net_sdn_detach(args):
1451     if not args.all and not args.id:
1452         print "--all or --id must be used"
1453         return 1
1454
1455     # Verify the network exists in the vim
1456     tenant = _get_tenant()
1457     datacenter = _get_datacenter(args.datacenter, tenant)
1458     result = _get_items('network', item_name_id=args.vim_net, datacenter=datacenter, tenant=tenant)
1459     content = yaml.load(result.content)
1460     if 'networks' in content:
1461         raise OpenmanoCLIError('More than one network in the vim named ' + args.vim_net + '. Use uuid instead')
1462     if 'error' in content:
1463         raise OpenmanoCLIError(yaml.safe_dump(content))
1464     network_uuid = content['network']['id']
1465
1466     if not args.force:
1467         r = raw_input("Confirm action' (y/N)? ")
1468         if len(r) == 0 or r[0].lower() != "y":
1469             return 0
1470
1471     if args.id:
1472         URLrequest = "http://%s:%s/openmano/%s/vim/%s/network/%s/detach/%s" % (
1473             mano_host, mano_port, tenant, datacenter, network_uuid, args.id)
1474     else:
1475         URLrequest = "http://%s:%s/openmano/%s/vim/%s/network/%s/detach" % (
1476             mano_host, mano_port, tenant, datacenter, network_uuid)
1477     mano_response = requests.delete(URLrequest)
1478     logger.debug("openmano response: %s", mano_response.text)
1479     result = _print_verbose(mano_response, args.verbose)
1480     return result
1481
1482
1483 def datacenter_net_action(args):
1484     if args.action == "net-update":
1485         print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-import' instead!!!"
1486         print
1487         args.action = "netmap-delete"
1488         args.netmap = None
1489         args.all = True
1490         r = datacenter_netmap_action(args)
1491         if r == 0:
1492             args.force = True
1493             args.action = "netmap-import"
1494             r = datacenter_netmap_action(args)
1495         return r
1496
1497     if args.action == "net-edit":
1498         args.netmap = args.net
1499         args.name = None
1500     elif args.action == "net-list":
1501         args.netmap = None
1502     elif args.action == "net-delete":
1503         args.netmap = args.net
1504         args.all = False
1505           
1506     args.action = "netmap" + args.action[3:]
1507     args.vim_name=None
1508     args.vim_id=None
1509     print "This command is deprecated, use 'openmano datacenter-%s' instead!!!" % args.action
1510     print
1511     return datacenter_netmap_action(args)
1512
1513 def datacenter_netmap_action(args):
1514     tenant = _get_tenant()
1515     datacenter = _get_datacenter(args.datacenter, tenant)
1516     #print "datacenter_netmap_action",args
1517     payload_req = None
1518     if args.verbose==None:
1519         args.verbose=0
1520     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1521     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/netmaps" %(mano_host, mano_port, tenant, datacenter)
1522         
1523     if args.action=="netmap-list":
1524         if args.netmap:
1525             URLrequest += "/" + args.netmap
1526             args.verbose += 1
1527         mano_response = requests.get(URLrequest)
1528             
1529     elif args.action=="netmap-delete":
1530         if args.netmap and args.all:
1531             print "you can not use a netmap name and the option --all at the same time"
1532             return 1
1533         if args.netmap:
1534             force_text= "Delete default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter)
1535             URLrequest += "/" + args.netmap
1536         elif args.all: 
1537             force_text="Delete all default netmaps from datacenter '%s' (y/N)? " % (datacenter)
1538         else:
1539             print "you must specify a netmap name or the option --all"
1540             return 1
1541         if not args.force:
1542             r = raw_input(force_text)
1543             if  len(r)>0  and r[0].lower()=="y":
1544                 pass
1545             else:
1546                 return 0
1547         mano_response = requests.delete(URLrequest, headers=headers_req)
1548     elif args.action=="netmap-import":
1549         if not args.force:
1550             r = raw_input("Create all the available networks from datacenter '%s' as default netmaps (y/N)? " % (datacenter))
1551             if  len(r)>0  and r[0].lower()=="y":
1552                 pass
1553             else:
1554                 return 0
1555         URLrequest += "/upload"
1556         mano_response = requests.post(URLrequest, headers=headers_req)
1557     elif args.action=="netmap-edit" or args.action=="netmap-create":
1558         if args.file:
1559             payload = _load_file_or_yaml(args.file)
1560         else:
1561             payload = {}
1562         if "netmap" not in payload:
1563             payload = {"netmap": payload}
1564         if args.name:
1565             payload["netmap"]["name"] = args.name
1566         if args.vim_id:
1567             payload["netmap"]["vim_id"] = args.vim_id
1568         if args.action=="netmap-create" and args.vim_name:
1569             payload["netmap"]["vim_name"] = args.vim_name
1570         payload_req = json.dumps(payload)
1571         logger.debug("openmano request: %s", payload_req)
1572         
1573         if args.action=="netmap-edit" and not args.force:
1574             if len(payload["netmap"]) == 0:
1575                 print "You must supply some parameter to edit"
1576                 return 1
1577             r = raw_input("Edit default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter))
1578             if  len(r)>0  and r[0].lower()=="y":
1579                 pass
1580             else:
1581                 return 0
1582             URLrequest += "/" + args.netmap
1583             mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1584         else: #netmap-create
1585             if "vim_name" not in payload["netmap"] and "vim_id" not in payload["netmap"]:
1586                 print "You must supply either --vim-id or --vim-name option; or include one of them in the file descriptor"
1587                 return 1
1588             mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1589
1590     logger.debug("openmano response: %s", mano_response.text )
1591     return _print_verbose(mano_response, args.verbose)
1592
1593
1594 def element_edit(args):
1595     element = _get_item_uuid(args.element, args.name)
1596     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1597     URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, args.element, element)
1598     payload=_load_file_or_yaml(args.file)
1599     if args.element[:-1] not in payload:
1600         payload = {args.element[:-1]: payload }
1601     payload_req = json.dumps(payload)
1602     
1603     #print payload_req
1604     if not args.force or (args.name==None and args.filer==None):
1605         r = raw_input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
1606         if  len(r)>0  and r[0].lower()=="y":
1607             pass
1608         else:
1609             return 0
1610     logger.debug("openmano request: %s", payload_req)
1611     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1612     logger.debug("openmano response: %s", mano_response.text )
1613     if args.verbose==None:
1614         args.verbose=0
1615     if args.name!=None:
1616         args.verbose += 1
1617     return _print_verbose(mano_response, args.verbose)
1618
1619
1620 def datacenter_edit(args):
1621     tenant = _get_tenant()
1622     element = _get_item_uuid('datacenters', args.name, tenant)
1623     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1624     URLrequest = "http://%s:%s/openmano/datacenters/%s" % (mano_host, mano_port, element)
1625
1626     has_arguments = False
1627     if args.file != None:
1628         has_arguments = True
1629         payload = _load_file_or_yaml(args.file)
1630     else:
1631         payload = {}
1632
1633     if args.sdn_controller != None:
1634         has_arguments = True
1635         if not 'config' in payload:
1636             payload['config'] = {}
1637         if not 'sdn-controller' in payload['config']:
1638             payload['config']['sdn-controller'] = {}
1639         if args.sdn_controller == 'null':
1640             payload['config']['sdn-controller'] = None
1641         else:
1642             payload['config']['sdn-controller'] = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
1643
1644     if not has_arguments:
1645         raise OpenmanoCLIError("At least one argument must be provided to modify the datacenter")
1646
1647     if 'datacenter' not in payload:
1648         payload = {'datacenter': payload}
1649     payload_req = json.dumps(payload)
1650
1651     # print payload_req
1652     if not args.force or (args.name == None and args.filer == None):
1653         r = raw_input(" Edit datacenter " + args.name + " (y/N)? ")
1654         if len(r) > 0 and r[0].lower() == "y":
1655             pass
1656         else:
1657             return 0
1658     logger.debug("openmano request: %s", payload_req)
1659     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1660     logger.debug("openmano response: %s", mano_response.text)
1661     if args.verbose == None:
1662         args.verbose = 0
1663     if args.name != None:
1664         args.verbose += 1
1665     return _print_verbose(mano_response, args.verbose)
1666
1667
1668 def version(args):
1669     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1670     URLrequest = "http://%s:%s/openmano/version" % (mano_host, mano_port)
1671
1672     mano_response = requests.get(URLrequest, headers=headers_req)
1673     logger.debug("openmano response: %s", mano_response.text)
1674     print mano_response.text
1675
1676
1677 global mano_host
1678 global mano_port
1679 global mano_tenant
1680
1681 if __name__=="__main__":
1682     
1683     mano_tenant = os.getenv('OPENMANO_TENANT', None)
1684     mano_host = os.getenv('OPENMANO_HOST',"localhost")
1685     mano_port = os.getenv('OPENMANO_PORT',"9090")
1686     mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
1687     
1688     main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
1689     main_parser.add_argument('--version', action='version', help="get version of this client",
1690                             version='%(prog)s client version ' + __version__ +
1691                                     " (Note: use '%(prog)s version' to get server version)")
1692
1693     subparsers = main_parser.add_subparsers(help='commands')
1694     
1695     parent_parser = argparse.ArgumentParser(add_help=False)
1696     parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
1697     parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1698
1699     config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
1700     config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
1701     config_parser.set_defaults(func=config)
1702
1703     version_parser = subparsers.add_parser('version', parents=[parent_parser], help="get server version")
1704     version_parser.set_defaults(func=version)
1705
1706     vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
1707     vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
1708     vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1709     vnf_create_parser.add_argument("--description", action="store", help="description of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1710     vnf_create_parser.add_argument("--image-path", action="store",  help="change image path locations (overwritten)")
1711     vnf_create_parser.add_argument("--image-name", action="store",  help="change image name (overwritten)")
1712     vnf_create_parser.add_argument("--image-checksum", action="store",  help="change image checksum (overwritten)")
1713     vnf_create_parser.set_defaults(func=vnf_create)
1714
1715     vnf_list_parser = subparsers.add_parser('vnf-list', parents=[parent_parser], help="lists information about a vnf")
1716     vnf_list_parser.add_argument("name", nargs='?', help="name of the VNF")
1717     vnf_list_parser.add_argument("-a", "--all", action="store_true", help="shows all vnfs, not only the owned or public ones")
1718     #vnf_list_parser.add_argument('--descriptor', help="prints the VNF descriptor", action="store_true")
1719     vnf_list_parser.set_defaults(func=vnf_list)
1720     
1721     vnf_delete_parser = subparsers.add_parser('vnf-delete', parents=[parent_parser], help="deletes a vnf from the catalogue")
1722     vnf_delete_parser.add_argument("name", action="store", help="name or uuid of the VNF to be deleted")
1723     vnf_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1724     vnf_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1725     vnf_delete_parser.set_defaults(func=vnf_delete)
1726     
1727     scenario_create_parser = subparsers.add_parser('scenario-create', parents=[parent_parser], help="adds a scenario into the OPENMANO DB")
1728     scenario_create_parser.add_argument("file", action="store", help="location of the YAML file describing the scenario").completer = FilesCompleter
1729     scenario_create_parser.add_argument("--name", action="store", help="name of the scenario (if it exists in the YAML scenario, it is overwritten)")
1730     scenario_create_parser.add_argument("--description", action="store", help="description of the scenario (if it exists in the YAML scenario, it is overwritten)")
1731     scenario_create_parser.set_defaults(func=scenario_create)
1732
1733     scenario_list_parser = subparsers.add_parser('scenario-list', parents=[parent_parser], help="lists information about a scenario")
1734     scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario")
1735     #scenario_list_parser.add_argument('--descriptor', help="prints the scenario descriptor", action="store_true")
1736     scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all scenarios, not only the owned or public ones")
1737     scenario_list_parser.set_defaults(func=scenario_list)
1738     
1739     scenario_delete_parser = subparsers.add_parser('scenario-delete', parents=[parent_parser], help="deletes a scenario from the OPENMANO DB")
1740     scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario to be deleted")
1741     scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1742     scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1743     scenario_delete_parser.set_defaults(func=scenario_delete)
1744
1745     scenario_deploy_parser = subparsers.add_parser('scenario-deploy', parents=[parent_parser], help="deploys a scenario")
1746     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be deployed")
1747     scenario_deploy_parser.add_argument("name", action="store", help="name of the instance")
1748     scenario_deploy_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1749     scenario_deploy_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1750     scenario_deploy_parser.add_argument("--description", action="store", help="description of the instance")
1751     scenario_deploy_parser.set_defaults(func=scenario_deploy)
1752     
1753     scenario_deploy_parser = subparsers.add_parser('scenario-verify', help="verifies if a scenario can be deployed (deploys it and deletes it)")
1754     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be verified")
1755     scenario_deploy_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1756     scenario_deploy_parser.set_defaults(func=scenario_verify)
1757     
1758     instance_scenario_create_parser = subparsers.add_parser('instance-scenario-create', parents=[parent_parser], help="deploys a scenario")
1759     instance_scenario_create_parser.add_argument("file", nargs='?', help="descriptor of the instance. Must be a file or yaml/json text")
1760     instance_scenario_create_parser.add_argument("--scenario", action="store", help="name or uuid of the scenario to be deployed")
1761     instance_scenario_create_parser.add_argument("--name", action="store", help="name of the instance")
1762     instance_scenario_create_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1763     instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1764     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")
1765     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")
1766     instance_scenario_create_parser.add_argument("--keypair", action="append", type=str, dest="keypair", help="public key for ssh access. Format '[user:]key1[,key2...]'. Can be used several times")
1767     instance_scenario_create_parser.add_argument("--keypair-auto", action="store_true", dest="keypair_auto", help="Inject the user ssh-keys found at $HOME/.ssh directory")
1768     instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
1769     instance_scenario_create_parser.set_defaults(func=instance_create)
1770
1771     instance_scenario_list_parser = subparsers.add_parser('instance-scenario-list', parents=[parent_parser], help="lists information about a scenario instance")
1772     instance_scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario instance")
1773     instance_scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all instance-scenarios, not only the owned")
1774     instance_scenario_list_parser.set_defaults(func=instance_scenario_list)
1775
1776     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)")
1777     instance_scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario instance to be deleted")
1778     instance_scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1779     instance_scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1780     instance_scenario_delete_parser.set_defaults(func=instance_scenario_delete)
1781     
1782     instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
1783     instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1784     instance_scenario_action_parser.add_argument("action", action="store", type=str, \
1785             choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console", "add_public_key","vdu-scaling"],\
1786             help="action to send")
1787     instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console: novnc; reboot: type; vdu-scaling: '[{vdu-id: xxx, type: create|delete, count: 1}]'")
1788     instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
1789     instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
1790     instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
1791
1792     action_parser = subparsers.add_parser('action-list', parents=[parent_parser], help="get action over an instance status")
1793     action_parser.add_argument("id", nargs='?', action="store", help="action id")
1794     action_parser.add_argument("--instance", action="store", help="fitler by this instance_id")
1795     action_parser.add_argument("--all", action="store", help="Not filter by tenant")
1796     action_parser.set_defaults(func=get_action)
1797
1798     #instance_scenario_status_parser = subparsers.add_parser('instance-scenario-status', help="show the status of a scenario instance")
1799     #instance_scenario_status_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1800     #instance_scenario_status_parser.set_defaults(func=instance_scenario_status)
1801     
1802     tenant_create_parser = subparsers.add_parser('tenant-create', parents=[parent_parser], help="creates a new tenant")
1803     tenant_create_parser.add_argument("name", action="store", help="name for the tenant")
1804     tenant_create_parser.add_argument("--description", action="store", help="description of the tenant")
1805     tenant_create_parser.set_defaults(func=tenant_create)
1806
1807     tenant_delete_parser = subparsers.add_parser('tenant-delete', parents=[parent_parser], help="deletes a tenant from the catalogue")
1808     tenant_delete_parser.add_argument("name", action="store", help="name or uuid of the tenant to be deleted")
1809     tenant_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1810     tenant_delete_parser.set_defaults(func=tenant_delete)
1811
1812     tenant_list_parser = subparsers.add_parser('tenant-list', parents=[parent_parser], help="lists information about a tenant")
1813     tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
1814     tenant_list_parser.set_defaults(func=tenant_list)
1815
1816     element_edit_parser = subparsers.add_parser('tenant-edit', parents=[parent_parser], help="edits one tenant")
1817     element_edit_parser.add_argument("name", help="name or uuid of the tenant")
1818     element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1819     element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1820     element_edit_parser.set_defaults(func=element_edit, element='tenants')
1821
1822     datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
1823     datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
1824     datacenter_create_parser.add_argument("url", action="store", help="url for the datacenter")
1825     datacenter_create_parser.add_argument("--url_admin", action="store", help="url for administration for the datacenter")
1826     datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
1827     datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1828     datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
1829     datacenter_create_parser.add_argument("--sdn-controller", action="store", help="Name or uuid of the SDN controller to be used", dest='sdn_controller')
1830     datacenter_create_parser.set_defaults(func=datacenter_create)
1831
1832     datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
1833     datacenter_delete_parser.add_argument("name", action="store", help="name or uuid of the datacenter to be deleted")
1834     datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1835     datacenter_delete_parser.set_defaults(func=datacenter_delete)
1836
1837     datacenter_edit_parser = subparsers.add_parser('datacenter-edit', parents=[parent_parser], help="Edit datacenter")
1838     datacenter_edit_parser.add_argument("name", help="name or uuid of the datacenter")
1839     datacenter_edit_parser.add_argument("--file", help="json/yaml text or file with the changes").completer = FilesCompleter
1840     datacenter_edit_parser.add_argument("--sdn-controller", action="store",
1841                                           help="Name or uuid of the SDN controller to be used. Specify 'null' to clear entry", dest='sdn_controller')
1842     datacenter_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
1843     datacenter_edit_parser.set_defaults(func=datacenter_edit)
1844
1845     datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
1846     datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
1847     datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
1848     datacenter_list_parser.set_defaults(func=datacenter_list)
1849
1850     datacenter_attach_parser = subparsers.add_parser('datacenter-attach', parents=[parent_parser], help="associates a datacenter to the operating tenant")
1851     datacenter_attach_parser.add_argument("name", help="name or uuid of the datacenter")
1852     datacenter_attach_parser.add_argument('--vim-tenant-id', action='store', help="specify a datacenter tenant to use. A new one is created by default")
1853     datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1854     datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1855     datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1856     datacenter_attach_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1857     datacenter_attach_parser.set_defaults(func=datacenter_attach)
1858
1859     datacenter_edit_vim_tenant_parser = subparsers.add_parser('datacenter-edit-vim-tenant', parents=[parent_parser],
1860                                                      help="Edit the association of a datacenter to the operating tenant")
1861     datacenter_edit_vim_tenant_parser.add_argument("name", help="name or uuid of the datacenter")
1862     datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-id', action='store',
1863                                           help="specify a datacenter tenant to use. A new one is created by default")
1864     datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1865     datacenter_edit_vim_tenant_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1866     datacenter_edit_vim_tenant_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1867     datacenter_edit_vim_tenant_parser.add_argument("--config", action="store",
1868                                           help="aditional configuration in json/yaml format")
1869     datacenter_edit_vim_tenant_parser.set_defaults(func=datacenter_edit_vim_tenant)
1870
1871     datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
1872     datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
1873     datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
1874     datacenter_detach_parser.set_defaults(func=datacenter_detach)
1875
1876     #=======================datacenter_sdn_port_mapping_xxx section=======================
1877     #datacenter_sdn_port_mapping_set
1878     datacenter_sdn_port_mapping_set_parser = subparsers.add_parser('datacenter-sdn-port-mapping-set',
1879                                                                    parents=[parent_parser],
1880                                                                    help="Load a file with the mapping of physical ports "
1881                                                                         "and the ports of the dataplaneswitch controlled "
1882                                                                         "by a datacenter")
1883     datacenter_sdn_port_mapping_set_parser.add_argument("name", action="store", help="specifies the datacenter")
1884     datacenter_sdn_port_mapping_set_parser.add_argument("file",
1885                                                         help="json/yaml text or file with the port mapping").completer = FilesCompleter
1886     datacenter_sdn_port_mapping_set_parser.add_argument("-f", "--force", action="store_true",
1887                                                           help="forces overwriting without asking")
1888     datacenter_sdn_port_mapping_set_parser.set_defaults(func=datacenter_sdn_port_mapping_set)
1889
1890     #datacenter_sdn_port_mapping_list
1891     datacenter_sdn_port_mapping_list_parser = subparsers.add_parser('datacenter-sdn-port-mapping-list',
1892                                                                     parents=[parent_parser],
1893                                                                     help="Show the SDN port mapping in a datacenter")
1894     datacenter_sdn_port_mapping_list_parser.add_argument("name", action="store", help="specifies the datacenter")
1895     datacenter_sdn_port_mapping_list_parser.set_defaults(func=datacenter_sdn_port_mapping_list)
1896
1897     # datacenter_sdn_port_mapping_clear
1898     datacenter_sdn_port_mapping_clear_parser = subparsers.add_parser('datacenter-sdn-port-mapping-clear',
1899                                                                     parents=[parent_parser],
1900                                                                     help="Clean the the SDN port mapping in a datacenter")
1901     datacenter_sdn_port_mapping_clear_parser.add_argument("name", action="store",
1902                                                          help="specifies the datacenter")
1903     datacenter_sdn_port_mapping_clear_parser.add_argument("-f", "--force", action="store_true",
1904                                               help="forces clearing without asking")
1905     datacenter_sdn_port_mapping_clear_parser.set_defaults(func=datacenter_sdn_port_mapping_clear)
1906     # =======================
1907
1908     # =======================sdn_controller_xxx section=======================
1909     # sdn_controller_create
1910     sdn_controller_create_parser = subparsers.add_parser('sdn-controller-create', parents=[parent_parser],
1911                                                         help="Creates an SDN controller entity within RO")
1912     sdn_controller_create_parser.add_argument("name", help="name of the SDN controller")
1913     sdn_controller_create_parser.add_argument("--description", action="store", help="description of the SDN controller")
1914     sdn_controller_create_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
1915     sdn_controller_create_parser.add_argument("--port", action="store", help="Port of the SDN controller")
1916     sdn_controller_create_parser.add_argument("--dpid", action="store",
1917                                              help="DPID of the dataplane switch controlled by this SDN controller")
1918     sdn_controller_create_parser.add_argument("--type", action="store",
1919                                              help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
1920     sdn_controller_create_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
1921     sdn_controller_create_parser.add_argument("--passwd", action="store", dest='password',
1922                                              help="password credentials for the SDN controller")
1923     sdn_controller_create_parser.set_defaults(func=sdn_controller_create)
1924
1925     # sdn_controller_edit
1926     sdn_controller_edit_parser = subparsers.add_parser('sdn-controller-edit', parents=[parent_parser],
1927                                                         help="Update one or more options of a SDN controller")
1928     sdn_controller_edit_parser.add_argument("name", help="name or uuid of the SDN controller", )
1929     sdn_controller_edit_parser.add_argument("--name", action="store", help="Update the name of the SDN controller",
1930                                               dest='new_name')
1931     sdn_controller_edit_parser.add_argument("--description", action="store", help="description of the SDN controller")
1932     sdn_controller_edit_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
1933     sdn_controller_edit_parser.add_argument("--port", action="store", help="Port of the SDN controller")
1934     sdn_controller_edit_parser.add_argument("--dpid", action="store",
1935                                              help="DPID of the dataplane switch controlled by this SDN controller")
1936     sdn_controller_edit_parser.add_argument("--type", action="store",
1937                                              help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
1938     sdn_controller_edit_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
1939     sdn_controller_edit_parser.add_argument("--password", action="store",
1940                                              help="password credentials for the SDN controller", dest='password')
1941     sdn_controller_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
1942     #TODO: include option --file
1943     sdn_controller_edit_parser.set_defaults(func=sdn_controller_edit)
1944
1945     #sdn_controller_list
1946     sdn_controller_list_parser = subparsers.add_parser('sdn-controller-list',
1947                                                                     parents=[parent_parser],
1948                                                                     help="List the SDN controllers")
1949     sdn_controller_list_parser.add_argument("name", nargs='?', help="name or uuid of the SDN controller")
1950     sdn_controller_list_parser.set_defaults(func=sdn_controller_list)
1951
1952     # sdn_controller_delete
1953     sdn_controller_delete_parser = subparsers.add_parser('sdn-controller-delete',
1954                                                                     parents=[parent_parser],
1955                                                                     help="Delete the the SDN controller")
1956     sdn_controller_delete_parser.add_argument("name", help="name or uuid of the SDN controller")
1957     sdn_controller_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1958     sdn_controller_delete_parser.set_defaults(func=sdn_controller_delete)
1959     # =======================
1960
1961     action_dict={'net-update': 'retrieves external networks from datacenter',
1962                  'net-edit': 'edits an external network',
1963                  'net-delete': 'deletes an external network',
1964                  'net-list': 'lists external networks from a datacenter'
1965                  }
1966     for item in action_dict:
1967         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1968         datacenter_action_parser.add_argument("datacenter", help="name or uuid of the datacenter")
1969         if item=='net-edit' or item=='net-delete':
1970             datacenter_action_parser.add_argument("net", help="name or uuid of the datacenter net")
1971         if item=='net-edit':
1972             datacenter_action_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1973         if item!='net-list':
1974             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1975         datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
1976
1977
1978     action_dict={'netmap-import': 'create network senario netmap base on the datacenter networks',
1979                  'netmap-create': 'create a new network senario netmap',
1980                  'netmap-edit':   'edit name of a network senario netmap',
1981                  'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
1982                  'netmap-list':   'list/show network scenario netmaps'
1983                  }
1984     for item in action_dict:
1985         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1986         datacenter_action_parser.add_argument("--datacenter", help="name or uuid of the datacenter")
1987         #if item=='net-add':
1988         #    datacenter_action_parser.add_argument("net", help="name of the network")
1989         if item=='netmap-delete':
1990             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to delete")
1991             datacenter_action_parser.add_argument("--all", action="store_true", help="delete all netmap of this datacenter")
1992             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1993         if item=='netmap-edit':
1994             datacenter_action_parser.add_argument("netmap", help="name or uuid of the datacenter netmap do edit")
1995             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file with the changes").completer = FilesCompleter
1996             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap")
1997             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1998             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1999         if item=='netmap-list':
2000             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to show")
2001         if item=='netmap-create':
2002             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file descriptor with the changes").completer = FilesCompleter
2003             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
2004             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
2005             datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
2006         if item=='netmap-import':
2007             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
2008         datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)
2009
2010     # =======================vim_net_sdn_xxx section=======================
2011     # vim_net_sdn_attach
2012     vim_net_sdn_attach_parser = subparsers.add_parser('vim-net-sdn-attach',
2013                                                       parents=[parent_parser],
2014                                                       help="Specify the port to access to an external network using SDN")
2015     vim_net_sdn_attach_parser.add_argument("vim_net", action="store",
2016                                                 help="Name/id of the network in the vim that will be used to connect to the external network")
2017     vim_net_sdn_attach_parser.add_argument("port", action="store", help="Specifies the port in the dataplane switch to access to the external network")
2018     vim_net_sdn_attach_parser.add_argument("--vlan", action="store", help="Specifies the vlan (if any) to use in the defined port")
2019     vim_net_sdn_attach_parser.add_argument("--mac", action="store", help="Specifies the MAC (if known) of the physical device that will be reachable by this external port")
2020     vim_net_sdn_attach_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2021     vim_net_sdn_attach_parser.set_defaults(func=vim_net_sdn_attach)
2022
2023     # vim_net_sdn_detach
2024     vim_net_sdn_detach_parser = subparsers.add_parser('vim-net-sdn-detach',
2025                                                            parents=[parent_parser],
2026                                                            help="Remove the port information to access to an external network using SDN")
2027
2028     vim_net_sdn_detach_parser.add_argument("vim_net", action="store", help="Name/id of the vim network")
2029     vim_net_sdn_detach_parser.add_argument("--id", action="store",help="Specify the uuid of the external ports from this network to be detached")
2030     vim_net_sdn_detach_parser.add_argument("--all", action="store_true", help="Detach all external ports from this network")
2031     vim_net_sdn_detach_parser.add_argument("-f", "--force", action="store_true", help="forces clearing without asking")
2032     vim_net_sdn_detach_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2033     vim_net_sdn_detach_parser.set_defaults(func=vim_net_sdn_detach)
2034     # =======================
2035
2036     for item in ("network", "tenant", "image"):
2037         if item=="network":
2038             command_name = 'vim-net'
2039         else:
2040             command_name = 'vim-'+item
2041         vim_item_list_parser = subparsers.add_parser(command_name + '-list', parents=[parent_parser], help="list the vim " + item + "s")
2042         vim_item_list_parser.add_argument("name", nargs='?', help="name or uuid of the " + item + "s")
2043         vim_item_list_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2044         vim_item_list_parser.set_defaults(func=vim_action, item=item, action="list")
2045
2046         vim_item_del_parser = subparsers.add_parser(command_name + '-delete', parents=[parent_parser], help="list the vim " + item + "s")
2047         vim_item_del_parser.add_argument("name", help="name or uuid of the " + item + "s")
2048         vim_item_del_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2049         vim_item_del_parser.set_defaults(func=vim_action, item=item, action="delete")
2050
2051         if item == "network" or item == "tenant":
2052             vim_item_create_parser = subparsers.add_parser(command_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
2053             vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the %s. Must be a file or yaml/json text" % item).completer = FilesCompleter
2054             vim_item_create_parser.add_argument("--name", action="store", help="name of the %s" % item  )
2055             vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2056             if item=="network":
2057                 vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
2058                 vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
2059                 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>'")
2060             else:
2061                 vim_item_create_parser.add_argument("--description", action="store", help="description of the %s" % item)
2062             vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
2063
2064     argcomplete.autocomplete(main_parser)
2065     
2066     try:
2067         args = main_parser.parse_args()
2068         #logging info
2069         level = logging.CRITICAL
2070         streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
2071         if "debug" in args and args.debug:
2072             level = logging.DEBUG
2073         logging.basicConfig(format=streamformat, level= level)
2074         logger = logging.getLogger('mano')
2075         logger.setLevel(level)
2076         result = args.func(args)
2077         if result == None:
2078             result = 0
2079         #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
2080     except (requests.exceptions.ConnectionError):
2081         print "Connection error: not possible to contact OPENMANO-SERVER (openmanod)"
2082         result = -2
2083     except (KeyboardInterrupt):
2084         print 'Exiting openmano'
2085         result = -3
2086     except (SystemExit, ArgumentParserError):
2087         result = -4
2088     except OpenmanoCLIError as e:
2089         print str(e)
2090         result = -5
2091     
2092     #print result
2093     exit(result)
2094