VNFs with only VLDs compatibility
[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.23-r533"
32 version_date = "May 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     myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
697     if args.netmap_use:
698         if "networks" not in myInstance["instance"]:
699             myInstance["instance"]["networks"] = {}
700         for net in args.netmap_use:
701             net_comma_list = net.split(",")
702             for net_comma in net_comma_list:
703                 net_tuple = net_comma.split("=")
704                 if len(net_tuple) != 2:
705                     print "error at netmap-use. Expected net-scenario=net-datacenter. (%s)?" % net_comma
706                     return
707                 net_scenario   = net_tuple[0].strip()
708                 net_datacenter = net_tuple[1].strip()
709                 if net_scenario not in myInstance["instance"]["networks"]:
710                     myInstance["instance"]["networks"][net_scenario] = {} 
711                 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
712                     myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
713                 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-use"] = net_datacenter
714     if args.netmap_create:
715         if "networks" not in myInstance["instance"]:
716             myInstance["instance"]["networks"] = {}
717         for net in args.netmap_create:
718             net_comma_list = net.split(",")
719             for net_comma in net_comma_list:
720                 net_tuple = net_comma.split("=")
721                 if len(net_tuple) == 1:
722                     net_scenario   = net_tuple[0].strip()
723                     net_datacenter = None
724                 elif len(net_tuple) == 2:
725                     net_scenario   = net_tuple[0].strip()
726                     net_datacenter = net_tuple[1].strip()
727                 else:
728                     print "error at netmap-create. Expected net-scenario=net-datacenter or net-scenario. (%s)?" % net_comma
729                     return
730                 if net_scenario not in myInstance["instance"]["networks"]:
731                     myInstance["instance"]["networks"][net_scenario] = {} 
732                 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
733                     myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
734                 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-create"] = net_datacenter
735     if args.keypair:
736         if "cloud-config" not in myInstance["instance"]:
737             myInstance["instance"]["cloud-config"] = {}
738         cloud_config = myInstance["instance"]["cloud-config"]
739         for key in args.keypair:
740             index = key.find(":")
741             if index<0:
742                 if "key-pairs" not in cloud_config:
743                     cloud_config["key-pairs"] = []
744                 cloud_config["key-pairs"].append(key)
745             else:
746                 user = key[:index]
747                 key_ = key[index+1:]
748                 key_list = key_.split(",")
749                 if "users" not in cloud_config:
750                     cloud_config["users"] = []
751                 cloud_config["users"].append({"name": user, "key-pairs": key_list  })
752     if args.keypair_auto:
753         try:
754             keys=[]
755             home = os.getenv("HOME")
756             user = os.getenv("USER")
757             files = os.listdir(home+'/.ssh')
758             for file in files:
759                 if file[-4:] == ".pub":
760                     with open(home+'/.ssh/'+file, 'r') as f:
761                         keys.append(f.read())
762             if not keys:
763                 print "Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh')
764                 return 1
765         except Exception as e:
766             print "Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e))
767             return 1
768         
769         if "cloud-config" not in myInstance["instance"]:
770             myInstance["instance"]["cloud-config"] = {}
771         cloud_config = myInstance["instance"]["cloud-config"]
772         if "key-pairs" not in cloud_config:
773             cloud_config["key-pairs"] = []
774         if user:
775             if "users" not in cloud_config:
776                 cloud_config["users"] = []
777             cloud_config["users"].append({"name": user, "key-pairs": keys })                    
778                         
779     payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
780     logger.debug("openmano request: %s", payload_req)
781     URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
782     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
783     logger.debug("openmano response: %s", mano_response.text )
784     if args.verbose==None:
785         args.verbose=0
786     
787     result = 0 if mano_response.status_code==200 else mano_response.status_code
788     content = mano_response.json()
789     #print json.dumps(content, indent=4)
790     if args.verbose >= 3:
791         print yaml.safe_dump(content, indent=4, default_flow_style=False)
792         return result
793
794     if mano_response.status_code == 200:
795         myoutput = "{:38} {:20}".format(content['uuid'], content['name'])
796         if args.verbose >=1:
797             myoutput = "{} {:20}".format(myoutput, content['created_at'])
798         if args.verbose >=2:
799             myoutput = "{} {:30}".format(myoutput, content['description'])
800         print myoutput
801     else:
802         print content['error']['description']
803     return result
804
805 def instance_scenario_list(args):
806     #print "instance-scenario-list",args
807     if args.all:
808         tenant = "any"
809     else:
810         tenant = _get_tenant()
811     if args.name:
812         toshow = _get_item_uuid("instances", args.name, tenant)
813         URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, toshow)
814     else:
815         URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
816     mano_response = requests.get(URLrequest)
817     logger.debug("openmano response: %s", mano_response.text )
818     content = mano_response.json()
819     #print json.dumps(content, indent=4)
820     if args.verbose==None:
821         args.verbose=0
822
823     result = 0 if mano_response.status_code==200 else mano_response.status_code
824     if mano_response.status_code == 200:
825         if not args.name:
826             if args.verbose >= 3:
827                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
828                 return result
829             if len(content['instances']) == 0:
830                 print "No scenario instances were found."
831                 return result
832             for instance in content['instances']:
833                 myoutput = "{:38} {:20}".format(instance['uuid'], instance['name'])
834                 if args.verbose >=1:
835                     myoutput = "{} {:20}".format(myoutput, instance['created_at'])
836                 print myoutput
837                 if args.verbose >=2:
838                     print "Description: %s" %instance['description']
839         else:
840             if args.verbose:
841                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
842                 return result
843             instance = content
844             print ("{:38} {:20} {:20}".format(instance['uuid'],instance['name'],instance['created_at']))
845             print ("Description: %s" %instance['description'])
846             print ("Template scenario id: {}".format(instance['scenario_id']))
847             print ("Template scenario name: {}".format(instance['scenario_name']))
848             print ("---------------------------------------")
849             print ("VNF instances: {}".format(len(instance['vnfs'])))
850             for vnf in instance['vnfs']:
851                 #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))
852                 print ("    {:38} {:20} Template vnf id: {:38}".format(vnf['uuid'], vnf['vnf_name'], vnf['vnf_id']))
853             if len(instance['nets'])>0:
854                 print "---------------------------------------"
855                 print "Internal nets:"
856                 for net in instance['nets']:
857                     if net['created']:
858                         print ("    {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
859                 print "---------------------------------------"
860                 print "External nets:"
861                 for net in instance['nets']:
862                     if not net['created']:
863                         print ("    {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
864             print ("---------------------------------------")
865             print ("VM instances:")
866             for vnf in instance['vnfs']:
867                 for vm in vnf['vms']:
868                     print ("    {:38} {:20} {:20} {:12} VIM ID: {}".format(vm['uuid'], vnf['vnf_name'], vm['name'],
869                                                                            vm['status'], vm['vim_vm_id']))
870     else:
871         print content['error']['description']
872         if args.verbose:
873             print yaml.safe_dump(content, indent=4, default_flow_style=False)
874     return result
875
876 def instance_scenario_status(args):
877     print "instance-scenario-status"
878     return 0
879
880 def instance_scenario_delete(args):
881     if args.all:
882         tenant = "any"
883     else:
884         tenant = _get_tenant()
885     todelete = _get_item_uuid("instances", args.name, tenant=tenant)
886     #print "instance-scenario-delete",args
887     if not args.force:
888         r = raw_input("Delete scenario instance %s (y/N)? " %(args.name))
889         if  not (len(r)>0  and r[0].lower()=="y"):
890             return
891     URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, todelete)
892     mano_response = requests.delete(URLrequest)
893     logger.debug("openmano response: %s", mano_response.text )
894     result = 0 if mano_response.status_code==200 else mano_response.status_code
895     content = mano_response.json()
896     #print json.dumps(content, indent=4)
897     if mano_response.status_code == 200:
898         print content['result']
899     else:
900         print content['error']['description']
901     return result
902
903 def get_action(args):
904     if not args.all:
905         tenant = _get_tenant()
906     else:
907         tenant = "any"
908     if not args.instance:
909         instance_id = "any"
910     else:
911         instance_id =args.instance
912     action_id = ""
913     if args.id:
914         action_id = "/" + args.id
915     URLrequest = "http://{}:{}/openmano/{}/instances/{}/action{}".format(mano_host, mano_port, tenant, instance_id,
916                                                                          action_id)
917     mano_response = requests.get(URLrequest)
918     logger.debug("openmano response: %s", mano_response.text )
919     if args.verbose == None:
920         args.verbose = 0
921     if args.id != None:
922         args.verbose += 1
923     return _print_verbose(mano_response, args.verbose)
924
925 def instance_scenario_action(args):
926     #print "instance-scenario-action", args
927     tenant = _get_tenant()
928     toact = _get_item_uuid("instances", args.name, tenant=tenant)
929     action={}
930     action[ args.action ] = yaml.safe_load(args.param)
931     if args.vnf:
932         action["vnfs"] = args.vnf
933     if args.vm:
934         action["vms"] = args.vm
935     
936     headers_req = {'content-type': 'application/json'}
937     payload_req = json.dumps(action, indent=4)
938     URLrequest = "http://%s:%s/openmano/%s/instances/%s/action" %(mano_host, mano_port, tenant, toact)
939     logger.debug("openmano request: %s", payload_req)
940     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
941     logger.debug("openmano response: %s", mano_response.text )
942     result = 0 if mano_response.status_code==200 else mano_response.status_code
943     content = mano_response.json()
944     # print json.dumps(content, indent=4)
945     if mano_response.status_code == 200:
946         if args.verbose:
947             print yaml.safe_dump(content, indent=4, default_flow_style=False)
948             return result
949         if "instance_action_id" in content:
950             print("instance_action_id={}".format(content["instance_action_id"]))
951         else:
952             for uuid,c in content.iteritems():
953                 print ("{:38} {:20} {:20}".format(uuid, c.get('name'), c.get('description')))
954     else:
955         print content['error']['description']
956     return result
957
958
959 def instance_vnf_list(args):
960     print "instance-vnf-list"
961     return 0
962
963 def instance_vnf_status(args):
964     print "instance-vnf-status"
965     return 0
966
967 def tenant_create(args):
968     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
969     tenant_dict={"name": args.name}
970     if args.description!=None:
971         tenant_dict["description"] = args.description 
972     payload_req = json.dumps( {"tenant": tenant_dict })
973     
974     #print payload_req
975         
976     URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
977     logger.debug("openmano request: %s", payload_req)
978     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
979     logger.debug("openmano response: %s", mano_response.text )
980     return _print_verbose(mano_response, args.verbose)
981
982 def tenant_list(args):
983     #print "tenant-list",args
984     if args.name:
985         toshow = _get_item_uuid("tenants", args.name)
986         URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, toshow)
987     else:
988         URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
989     mano_response = requests.get(URLrequest)
990     logger.debug("openmano response: %s", mano_response.text )
991     if args.verbose==None:
992         args.verbose=0
993     if args.name!=None:
994         args.verbose += 1
995     return _print_verbose(mano_response, args.verbose)
996
997 def tenant_delete(args):
998     #print "tenant-delete",args
999     todelete = _get_item_uuid("tenants", args.name)
1000     if not args.force:
1001         r = raw_input("Delete tenant %s (y/N)? " %(args.name))
1002         if  not (len(r)>0  and r[0].lower()=="y"):
1003             return 0
1004     URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, todelete)
1005     mano_response = requests.delete(URLrequest)
1006     logger.debug("openmano response: %s", mano_response.text )
1007     result = 0 if mano_response.status_code==200 else mano_response.status_code
1008     content = mano_response.json()
1009     #print json.dumps(content, indent=4)
1010     if mano_response.status_code == 200:
1011         print content['result']
1012     else:
1013         print content['error']['description']
1014     return result
1015
1016 def datacenter_attach(args):
1017     tenant = _get_tenant()
1018     datacenter = _get_datacenter(args.name)
1019     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1020     
1021     datacenter_dict={}
1022     if args.vim_tenant_id != None:
1023         datacenter_dict['vim_tenant'] = args.vim_tenant_id
1024     if args.vim_tenant_name != None:
1025         datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
1026     if args.user != None:
1027         datacenter_dict['vim_username'] = args.user
1028     if args.password != None:
1029         datacenter_dict['vim_password'] = args.password
1030     if args.config!=None:
1031         datacenter_dict["config"] = _load_file_or_yaml(args.config)
1032
1033     payload_req = json.dumps( {"datacenter": datacenter_dict })
1034
1035     #print payload_req
1036         
1037     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
1038     logger.debug("openmano request: %s", payload_req)
1039     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1040     logger.debug("openmano response: %s", mano_response.text )
1041     result = _print_verbose(mano_response, args.verbose)
1042     #provide addional information if error
1043     if mano_response.status_code != 200:
1044         content = mano_response.json()
1045         if "already in use for  'name'" in content['error']['description'] and \
1046                 "to database vim_tenants table" in content['error']['description']:
1047             print "Try to specify a different name with --vim-tenant-name"
1048     return result
1049
1050
1051 def datacenter_edit_vim_tenant(args):
1052     tenant = _get_tenant()
1053     datacenter = _get_datacenter(args.name)
1054     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1055
1056     if not (args.vim_tenant_id or args.vim_tenant_name or args.user or args.password or args.config):
1057         raise OpenmanoCLIError("Error. At least one parameter must be updated.")
1058
1059     datacenter_dict = {}
1060     if args.vim_tenant_id != None:
1061         datacenter_dict['vim_tenant'] = args.vim_tenant_id
1062     if args.vim_tenant_name != None:
1063         datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
1064     if args.user != None:
1065         datacenter_dict['vim_username'] = args.user
1066     if args.password != None:
1067         datacenter_dict['vim_password'] = args.password
1068     if args.config != None:
1069         datacenter_dict["config"] = _load_file_or_yaml(args.config)
1070     payload_req = json.dumps({"datacenter": datacenter_dict})
1071
1072     # print payload_req
1073
1074     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" % (mano_host, mano_port, tenant, datacenter)
1075     logger.debug("openmano request: %s", payload_req)
1076     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1077     logger.debug("openmano response: %s", mano_response.text)
1078     result = _print_verbose(mano_response, args.verbose)
1079
1080     return result
1081
1082 def datacenter_detach(args):
1083     if args.all:
1084         tenant = "any"
1085     else:
1086         tenant = _get_tenant()
1087     datacenter = _get_datacenter(args.name, tenant)
1088     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1089     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
1090     mano_response = requests.delete(URLrequest, headers=headers_req)
1091     logger.debug("openmano response: %s", mano_response.text )
1092     content = mano_response.json()
1093     #print json.dumps(content, indent=4)
1094     result = 0 if mano_response.status_code==200 else mano_response.status_code
1095     if mano_response.status_code == 200:
1096         print content['result']
1097     else:
1098         print content['error']['description']
1099     return result
1100
1101 def datacenter_create(args):
1102     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1103     datacenter_dict={"name": args.name, "vim_url": args.url}
1104     if args.description!=None:
1105         datacenter_dict["description"] = args.description 
1106     if args.type!=None:
1107         datacenter_dict["type"] = args.type 
1108     if args.url!=None:
1109         datacenter_dict["vim_url_admin"] = args.url_admin 
1110     if args.config!=None:
1111         datacenter_dict["config"] = _load_file_or_yaml(args.config)
1112     if args.sdn_controller!=None:
1113         tenant = _get_tenant()
1114         sdn_controller = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
1115         if not 'config' in datacenter_dict:
1116             datacenter_dict['config'] = {}
1117         datacenter_dict['config']['sdn-controller'] = sdn_controller
1118     payload_req = json.dumps( {"datacenter": datacenter_dict })
1119     
1120     #print payload_req
1121         
1122     URLrequest = "http://%s:%s/openmano/datacenters" %(mano_host, mano_port)
1123     logger.debug("openmano request: %s", payload_req)
1124     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1125     logger.debug("openmano response: %s", mano_response.text )
1126     return _print_verbose(mano_response, args.verbose)
1127
1128 def datacenter_delete(args):
1129     #print "datacenter-delete",args
1130     todelete = _get_item_uuid("datacenters", args.name, "any")
1131     if not args.force:
1132         r = raw_input("Delete datacenter %s (y/N)? " %(args.name))
1133         if  not (len(r)>0  and r[0].lower()=="y"):
1134             return 0
1135     URLrequest = "http://%s:%s/openmano/datacenters/%s" %(mano_host, mano_port, todelete)
1136     mano_response = requests.delete(URLrequest)
1137     logger.debug("openmano response: %s", mano_response.text )
1138     result = 0 if mano_response.status_code==200 else mano_response.status_code
1139     content = mano_response.json()
1140     #print json.dumps(content, indent=4)
1141     if mano_response.status_code == 200:
1142         print content['result']
1143     else:
1144         print content['error']['description']
1145     return result
1146
1147
1148 def datacenter_list(args):
1149     #print "datacenter-list",args
1150     tenant='any' if args.all else _get_tenant()
1151     
1152     if args.name:
1153         toshow = _get_item_uuid("datacenters", args.name, tenant) 
1154         URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, toshow)
1155     else:
1156         URLrequest = "http://%s:%s/openmano/%s/datacenters" %(mano_host, mano_port, tenant)
1157     mano_response = requests.get(URLrequest)
1158     logger.debug("openmano response: %s", mano_response.text )
1159     if args.verbose==None:
1160         args.verbose=0
1161     if args.name!=None:
1162         args.verbose += 1
1163     return _print_verbose(mano_response, args.verbose)
1164
1165
1166 def datacenter_sdn_port_mapping_set(args):
1167     tenant = _get_tenant()
1168     datacenter = _get_datacenter(args.name, tenant)
1169     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1170
1171     if not args.file:
1172         raise OpenmanoCLIError(
1173             "No yaml/json has been provided specifying the SDN port mapping")
1174     sdn_port_mapping = _load_file_or_yaml(args.file)
1175     payload_req = json.dumps({"sdn_port_mapping": sdn_port_mapping})
1176
1177     # read
1178     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1179     mano_response = requests.get(URLrequest)
1180     logger.debug("openmano response: %s", mano_response.text)
1181     port_mapping = mano_response.json()
1182     if mano_response.status_code != 200:
1183         str(mano_response.json())
1184         raise OpenmanoCLIError("openmano client error: {}".format(port_mapping['error']['description']))
1185     if len(port_mapping["sdn_port_mapping"]["ports_mapping"]) > 0:
1186         if not args.force:
1187             r = raw_input("Datacenter %s already contains a port mapping. Overwrite? (y/N)? " % (datacenter))
1188             if not (len(r) > 0 and r[0].lower() == "y"):
1189                 return 0
1190
1191         # clear
1192         URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1193         mano_response = requests.delete(URLrequest)
1194         logger.debug("openmano response: %s", mano_response.text)
1195         if mano_response.status_code != 200:
1196             return _print_verbose(mano_response, args.verbose)
1197
1198     # set
1199     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1200     logger.debug("openmano request: %s", payload_req)
1201     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1202     logger.debug("openmano response: %s", mano_response.text)
1203     return _print_verbose(mano_response, args.verbose)
1204
1205
1206 def datacenter_sdn_port_mapping_list(args):
1207     tenant = _get_tenant()
1208     datacenter = _get_datacenter(args.name, tenant)
1209
1210     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1211     mano_response = requests.get(URLrequest)
1212     logger.debug("openmano response: %s", mano_response.text)
1213
1214     return _print_verbose(mano_response, 4)
1215
1216
1217 def datacenter_sdn_port_mapping_clear(args):
1218     tenant = _get_tenant()
1219     datacenter = _get_datacenter(args.name, tenant)
1220
1221     if not args.force:
1222         r = raw_input("Clean SDN port mapping for datacenter %s (y/N)? " %(datacenter))
1223         if not (len(r) > 0 and r[0].lower() == "y"):
1224             return 0
1225
1226     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1227     mano_response = requests.delete(URLrequest)
1228     logger.debug("openmano response: %s", mano_response.text)
1229
1230     return _print_verbose(mano_response, args.verbose)
1231
1232
1233 def sdn_controller_create(args):
1234     tenant = _get_tenant()
1235     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1236
1237     error_msg=[]
1238     if not args.ip: error_msg.append("'ip'")
1239     if not args.port: error_msg.append("'port'")
1240     if not args.dpid: error_msg.append("'dpid'")
1241     if not args.type: error_msg.append("'type'")
1242     if error_msg:
1243         raise OpenmanoCLIError("The following arguments are required: " + ",".join(error_msg))
1244
1245     controller_dict = {}
1246     controller_dict['name'] = args.name
1247     controller_dict['ip'] = args.ip
1248     controller_dict['port'] = int(args.port)
1249     controller_dict['dpid'] = args.dpid
1250     controller_dict['type'] = args.type
1251     if args.description != None:
1252         controller_dict['description'] = args.description
1253     if args.user != None:
1254         controller_dict['user'] = args.user
1255     if args.password != None:
1256         controller_dict['password'] = args.password
1257
1258     payload_req = json.dumps({"sdn_controller": controller_dict})
1259
1260     # print payload_req
1261
1262     URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" % (mano_host, mano_port, tenant)
1263     logger.debug("openmano request: %s", payload_req)
1264     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1265     logger.debug("openmano response: %s", mano_response.text)
1266     result = _print_verbose(mano_response, args.verbose)
1267     return result
1268
1269
1270 def sdn_controller_edit(args):
1271     tenant = _get_tenant()
1272     controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
1273     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1274
1275     controller_dict = {}
1276     if args.new_name:
1277         controller_dict['name'] = args.new_name
1278     if args.ip:
1279         controller_dict['ip'] = args.ip
1280     if args.port:
1281         controller_dict['port'] = int(args.port)
1282     if args.dpid:
1283         controller_dict['dpid'] = args.dpid
1284     if args.type:
1285         controller_dict['type'] = args.type
1286     if args.description:
1287         controller_dict['description'] = args.description
1288     if args.user:
1289         controller_dict['user'] = args.user
1290     if args.password:
1291         controller_dict['password'] = args.password
1292
1293     if not controller_dict:
1294         raise OpenmanoCLIError("At least one parameter must be edited")
1295
1296     if not args.force:
1297         r = raw_input("Update SDN controller {} (y/N)? ".format(args.name))
1298         if not (len(r) > 0 and r[0].lower() == "y"):
1299             return 0
1300
1301     payload_req = json.dumps({"sdn_controller": controller_dict})
1302     # print payload_req
1303
1304     URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
1305     logger.debug("openmano request: %s", payload_req)
1306     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1307     logger.debug("openmano response: %s", mano_response.text)
1308     result = _print_verbose(mano_response, args.verbose)
1309     return result
1310
1311
1312 def sdn_controller_list(args):
1313     tenant = _get_tenant()
1314     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1315
1316     if args.name:
1317         toshow = _get_item_uuid("sdn_controllers", args.name, tenant)
1318         URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" %(mano_host, mano_port, tenant, toshow)
1319     else:
1320         URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" %(mano_host, mano_port, tenant)
1321     #print URLrequest
1322     mano_response = requests.get(URLrequest)
1323     logger.debug("openmano response: %s", mano_response.text )
1324     if args.verbose==None:
1325         args.verbose=0
1326     if args.name!=None:
1327         args.verbose += 1
1328
1329     # json.dumps(mano_response.json(), indent=4)
1330     return _print_verbose(mano_response, args.verbose)
1331
1332
1333 def sdn_controller_delete(args):
1334     tenant = _get_tenant()
1335     controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
1336
1337     if not args.force:
1338         r = raw_input("Delete SDN controller %s (y/N)? " % (args.name))
1339         if not (len(r) > 0 and r[0].lower() == "y"):
1340             return 0
1341
1342     URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
1343     mano_response = requests.delete(URLrequest)
1344     logger.debug("openmano response: %s", mano_response.text)
1345     return _print_verbose(mano_response, args.verbose)
1346
1347 def vim_action(args):
1348     #print "datacenter-net-action",args
1349     tenant = _get_tenant()
1350     datacenter = _get_datacenter(args.datacenter, tenant)
1351     if args.verbose==None:
1352         args.verbose=0
1353     if args.action=="list":
1354         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
1355         if args.name!=None:
1356             args.verbose += 1
1357             URLrequest += "/" + args.name
1358         mano_response = requests.get(URLrequest)
1359         logger.debug("openmano response: %s", mano_response.text )
1360         return _print_verbose(mano_response, args.verbose)
1361     elif args.action=="delete":
1362         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss/%s" %(mano_host, mano_port, tenant, datacenter, args.item, args.name)
1363         mano_response = requests.delete(URLrequest)
1364         logger.debug("openmano response: %s", mano_response.text )
1365         result = 0 if mano_response.status_code==200 else mano_response.status_code
1366         content = mano_response.json()
1367         #print json.dumps(content, indent=4)
1368         if mano_response.status_code == 200:
1369             print content['result']
1370         else:
1371             print content['error']['description']
1372         return result
1373     elif args.action=="create":
1374         headers_req = {'content-type': 'application/yaml'}
1375         if args.file:
1376             create_dict = _load_file_or_yaml(args.file)
1377             if args.item not in create_dict:
1378                 create_dict = {args.item: create_dict}
1379         else:
1380             create_dict = {args.item:{}}
1381         if args.name:
1382             create_dict[args.item]['name'] = args.name
1383         #if args.description:
1384         #    create_dict[args.item]['description'] = args.description
1385         if args.item=="network":
1386             if args.bind_net:
1387                 create_dict[args.item]['bind_net'] = args.bind_net
1388             if args.type:
1389                 create_dict[args.item]['type'] = args.type
1390             if args.shared:
1391                 create_dict[args.item]['shared'] = args.shared
1392         if "name" not in create_dict[args.item]:
1393             print "You must provide a name in the descriptor file or with the --name option"
1394             return
1395         payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
1396         logger.debug("openmano request: %s", payload_req)
1397         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
1398         mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
1399         logger.debug("openmano response: %s", mano_response.text )
1400         if args.verbose==None:
1401             args.verbose=0
1402         return _print_verbose(mano_response, args.verbose)
1403
1404
1405 def _get_items(item, item_name_id=None, datacenter=None, tenant=None):
1406     URLrequest = "http://%s:%s/openmano" %(mano_host, mano_port)
1407     if tenant:
1408         URLrequest += "/" + tenant
1409     if datacenter:
1410         URLrequest += "/vim/" + datacenter
1411     if item:
1412         URLrequest += "/" + item +"s"
1413     if item_name_id:
1414         URLrequest += "/" + item_name_id
1415     mano_response = requests.get(URLrequest)
1416     logger.debug("openmano response: %s", mano_response.text )
1417
1418     return mano_response
1419
1420
1421 def vim_net_sdn_attach(args):
1422     #Verify the network exists in the vim
1423     tenant = _get_tenant()
1424     datacenter = _get_datacenter(args.datacenter, tenant)
1425     result = _get_items('network', item_name_id=args.vim_net, datacenter=datacenter, tenant=tenant)
1426     content = yaml.load(result.content)
1427     if 'networks' in content:
1428         raise OpenmanoCLIError('More than one network in the vim named ' + args.vim_net + '. Use uuid instead')
1429     if 'error' in content:
1430         raise OpenmanoCLIError(yaml.safe_dump(content))
1431     network_uuid = content['network']['id']
1432
1433     #Make call to attach the dataplane port to the SND network associated to the vim network
1434     headers_req = {'content-type': 'application/yaml'}
1435     payload_req = {'port': args.port}
1436     if args.vlan:
1437         payload_req['vlan'] = int(args.vlan)
1438     if args.mac:
1439         payload_req['mac'] = args.mac
1440
1441     URLrequest = "http://%s:%s/openmano/%s/vim/%s/network/%s/attach" % (mano_host, mano_port, tenant, datacenter, network_uuid)
1442     logger.debug("openmano request: %s", payload_req)
1443     mano_response = requests.post(URLrequest, headers=headers_req, data=json.dumps(payload_req))
1444     logger.debug("openmano response: %s", mano_response.text)
1445     result = _print_verbose(mano_response, args.verbose)
1446     return result
1447
1448
1449 def vim_net_sdn_detach(args):
1450     if not args.all and not args.id:
1451         print "--all or --id must be used"
1452         return 1
1453
1454     # Verify the network exists in the vim
1455     tenant = _get_tenant()
1456     datacenter = _get_datacenter(args.datacenter, tenant)
1457     result = _get_items('network', item_name_id=args.vim_net, datacenter=datacenter, tenant=tenant)
1458     content = yaml.load(result.content)
1459     if 'networks' in content:
1460         raise OpenmanoCLIError('More than one network in the vim named ' + args.vim_net + '. Use uuid instead')
1461     if 'error' in content:
1462         raise OpenmanoCLIError(yaml.safe_dump(content))
1463     network_uuid = content['network']['id']
1464
1465     if not args.force:
1466         r = raw_input("Confirm action' (y/N)? ")
1467         if len(r) == 0 or r[0].lower() != "y":
1468             return 0
1469
1470     if args.id:
1471         URLrequest = "http://%s:%s/openmano/%s/vim/%s/network/%s/detach/%s" % (
1472             mano_host, mano_port, tenant, datacenter, network_uuid, args.id)
1473     else:
1474         URLrequest = "http://%s:%s/openmano/%s/vim/%s/network/%s/detach" % (
1475             mano_host, mano_port, tenant, datacenter, network_uuid)
1476     mano_response = requests.delete(URLrequest)
1477     logger.debug("openmano response: %s", mano_response.text)
1478     result = _print_verbose(mano_response, args.verbose)
1479     return result
1480
1481
1482 def datacenter_net_action(args):
1483     if args.action == "net-update":
1484         print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-import' instead!!!"
1485         print
1486         args.action = "netmap-delete"
1487         args.netmap = None
1488         args.all = True
1489         r = datacenter_netmap_action(args)
1490         if r == 0:
1491             args.force = True
1492             args.action = "netmap-import"
1493             r = datacenter_netmap_action(args)
1494         return r
1495
1496     if args.action == "net-edit":
1497         args.netmap = args.net
1498         args.name = None
1499     elif args.action == "net-list":
1500         args.netmap = None
1501     elif args.action == "net-delete":
1502         args.netmap = args.net
1503         args.all = False
1504           
1505     args.action = "netmap" + args.action[3:]
1506     args.vim_name=None
1507     args.vim_id=None
1508     print "This command is deprecated, use 'openmano datacenter-%s' instead!!!" % args.action
1509     print
1510     return datacenter_netmap_action(args)
1511
1512 def datacenter_netmap_action(args):
1513     tenant = _get_tenant()
1514     datacenter = _get_datacenter(args.datacenter, tenant)
1515     #print "datacenter_netmap_action",args
1516     payload_req = None
1517     if args.verbose==None:
1518         args.verbose=0
1519     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1520     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/netmaps" %(mano_host, mano_port, tenant, datacenter)
1521         
1522     if args.action=="netmap-list":
1523         if args.netmap:
1524             URLrequest += "/" + args.netmap
1525             args.verbose += 1
1526         mano_response = requests.get(URLrequest)
1527             
1528     elif args.action=="netmap-delete":
1529         if args.netmap and args.all:
1530             print "you can not use a netmap name and the option --all at the same time"
1531             return 1
1532         if args.netmap:
1533             force_text= "Delete default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter)
1534             URLrequest += "/" + args.netmap
1535         elif args.all: 
1536             force_text="Delete all default netmaps from datacenter '%s' (y/N)? " % (datacenter)
1537         else:
1538             print "you must specify a netmap name or the option --all"
1539             return 1
1540         if not args.force:
1541             r = raw_input(force_text)
1542             if  len(r)>0  and r[0].lower()=="y":
1543                 pass
1544             else:
1545                 return 0
1546         mano_response = requests.delete(URLrequest, headers=headers_req)
1547     elif args.action=="netmap-import":
1548         if not args.force:
1549             r = raw_input("Create all the available networks from datacenter '%s' as default netmaps (y/N)? " % (datacenter))
1550             if  len(r)>0  and r[0].lower()=="y":
1551                 pass
1552             else:
1553                 return 0
1554         URLrequest += "/upload"
1555         mano_response = requests.post(URLrequest, headers=headers_req)
1556     elif args.action=="netmap-edit" or args.action=="netmap-create":
1557         if args.file:
1558             payload = _load_file_or_yaml(args.file)
1559         else:
1560             payload = {}
1561         if "netmap" not in payload:
1562             payload = {"netmap": payload}
1563         if args.name:
1564             payload["netmap"]["name"] = args.name
1565         if args.vim_id:
1566             payload["netmap"]["vim_id"] = args.vim_id
1567         if args.action=="netmap-create" and args.vim_name:
1568             payload["netmap"]["vim_name"] = args.vim_name
1569         payload_req = json.dumps(payload)
1570         logger.debug("openmano request: %s", payload_req)
1571         
1572         if args.action=="netmap-edit" and not args.force:
1573             if len(payload["netmap"]) == 0:
1574                 print "You must supply some parameter to edit"
1575                 return 1
1576             r = raw_input("Edit default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter))
1577             if  len(r)>0  and r[0].lower()=="y":
1578                 pass
1579             else:
1580                 return 0
1581             URLrequest += "/" + args.netmap
1582             mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1583         else: #netmap-create
1584             if "vim_name" not in payload["netmap"] and "vim_id" not in payload["netmap"]:
1585                 print "You must supply either --vim-id or --vim-name option; or include one of them in the file descriptor"
1586                 return 1
1587             mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1588
1589     logger.debug("openmano response: %s", mano_response.text )
1590     return _print_verbose(mano_response, args.verbose)
1591
1592
1593 def element_edit(args):
1594     element = _get_item_uuid(args.element, args.name)
1595     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1596     URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, args.element, element)
1597     payload=_load_file_or_yaml(args.file)
1598     if args.element[:-1] not in payload:
1599         payload = {args.element[:-1]: payload }
1600     payload_req = json.dumps(payload)
1601     
1602     #print payload_req
1603     if not args.force or (args.name==None and args.filer==None):
1604         r = raw_input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
1605         if  len(r)>0  and r[0].lower()=="y":
1606             pass
1607         else:
1608             return 0
1609     logger.debug("openmano request: %s", payload_req)
1610     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1611     logger.debug("openmano response: %s", mano_response.text )
1612     if args.verbose==None:
1613         args.verbose=0
1614     if args.name!=None:
1615         args.verbose += 1
1616     return _print_verbose(mano_response, args.verbose)
1617
1618
1619 def datacenter_edit(args):
1620     tenant = _get_tenant()
1621     element = _get_item_uuid('datacenters', args.name, tenant)
1622     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1623     URLrequest = "http://%s:%s/openmano/datacenters/%s" % (mano_host, mano_port, element)
1624
1625     has_arguments = False
1626     if args.file != None:
1627         has_arguments = True
1628         payload = _load_file_or_yaml(args.file)
1629     else:
1630         payload = {}
1631
1632     if args.sdn_controller != None:
1633         has_arguments = True
1634         if not 'config' in payload:
1635             payload['config'] = {}
1636         if not 'sdn-controller' in payload['config']:
1637             payload['config']['sdn-controller'] = {}
1638         if args.sdn_controller == 'null':
1639             payload['config']['sdn-controller'] = None
1640         else:
1641             payload['config']['sdn-controller'] = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
1642
1643     if not has_arguments:
1644         raise OpenmanoCLIError("At least one argument must be provided to modify the datacenter")
1645
1646     if 'datacenter' not in payload:
1647         payload = {'datacenter': payload}
1648     payload_req = json.dumps(payload)
1649
1650     # print payload_req
1651     if not args.force or (args.name == None and args.filer == None):
1652         r = raw_input(" Edit datacenter " + args.name + " (y/N)? ")
1653         if len(r) > 0 and r[0].lower() == "y":
1654             pass
1655         else:
1656             return 0
1657     logger.debug("openmano request: %s", payload_req)
1658     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1659     logger.debug("openmano response: %s", mano_response.text)
1660     if args.verbose == None:
1661         args.verbose = 0
1662     if args.name != None:
1663         args.verbose += 1
1664     return _print_verbose(mano_response, args.verbose)
1665
1666
1667 def version(args):
1668     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1669     URLrequest = "http://%s:%s/openmano/version" % (mano_host, mano_port)
1670
1671     mano_response = requests.get(URLrequest, headers=headers_req)
1672     logger.debug("openmano response: %s", mano_response.text)
1673     print mano_response.text
1674
1675
1676 global mano_host
1677 global mano_port
1678 global mano_tenant
1679
1680 if __name__=="__main__":
1681     
1682     mano_tenant = os.getenv('OPENMANO_TENANT', None)
1683     mano_host = os.getenv('OPENMANO_HOST',"localhost")
1684     mano_port = os.getenv('OPENMANO_PORT',"9090")
1685     mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
1686     
1687     main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
1688     main_parser.add_argument('--version', action='version', help="get version of this client",
1689                             version='%(prog)s client version ' + __version__ +
1690                                     " (Note: use '%(prog)s version' to get server version)")
1691
1692     subparsers = main_parser.add_subparsers(help='commands')
1693     
1694     parent_parser = argparse.ArgumentParser(add_help=False)
1695     parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
1696     parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1697
1698     config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
1699     config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
1700     config_parser.set_defaults(func=config)
1701
1702     version_parser = subparsers.add_parser('version', parents=[parent_parser], help="get server version")
1703     version_parser.set_defaults(func=version)
1704
1705     vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
1706     vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
1707     vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1708     vnf_create_parser.add_argument("--description", action="store", help="description of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1709     vnf_create_parser.add_argument("--image-path", action="store",  help="change image path locations (overwritten)")
1710     vnf_create_parser.add_argument("--image-name", action="store",  help="change image name (overwritten)")
1711     vnf_create_parser.add_argument("--image-checksum", action="store",  help="change image checksum (overwritten)")
1712     vnf_create_parser.set_defaults(func=vnf_create)
1713
1714     vnf_list_parser = subparsers.add_parser('vnf-list', parents=[parent_parser], help="lists information about a vnf")
1715     vnf_list_parser.add_argument("name", nargs='?', help="name of the VNF")
1716     vnf_list_parser.add_argument("-a", "--all", action="store_true", help="shows all vnfs, not only the owned or public ones")
1717     #vnf_list_parser.add_argument('--descriptor', help="prints the VNF descriptor", action="store_true")
1718     vnf_list_parser.set_defaults(func=vnf_list)
1719     
1720     vnf_delete_parser = subparsers.add_parser('vnf-delete', parents=[parent_parser], help="deletes a vnf from the catalogue")
1721     vnf_delete_parser.add_argument("name", action="store", help="name or uuid of the VNF to be deleted")
1722     vnf_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1723     vnf_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1724     vnf_delete_parser.set_defaults(func=vnf_delete)
1725     
1726     scenario_create_parser = subparsers.add_parser('scenario-create', parents=[parent_parser], help="adds a scenario into the OPENMANO DB")
1727     scenario_create_parser.add_argument("file", action="store", help="location of the YAML file describing the scenario").completer = FilesCompleter
1728     scenario_create_parser.add_argument("--name", action="store", help="name of the scenario (if it exists in the YAML scenario, it is overwritten)")
1729     scenario_create_parser.add_argument("--description", action="store", help="description of the scenario (if it exists in the YAML scenario, it is overwritten)")
1730     scenario_create_parser.set_defaults(func=scenario_create)
1731
1732     scenario_list_parser = subparsers.add_parser('scenario-list', parents=[parent_parser], help="lists information about a scenario")
1733     scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario")
1734     #scenario_list_parser.add_argument('--descriptor', help="prints the scenario descriptor", action="store_true")
1735     scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all scenarios, not only the owned or public ones")
1736     scenario_list_parser.set_defaults(func=scenario_list)
1737     
1738     scenario_delete_parser = subparsers.add_parser('scenario-delete', parents=[parent_parser], help="deletes a scenario from the OPENMANO DB")
1739     scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario to be deleted")
1740     scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1741     scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1742     scenario_delete_parser.set_defaults(func=scenario_delete)
1743
1744     scenario_deploy_parser = subparsers.add_parser('scenario-deploy', parents=[parent_parser], help="deploys a scenario")
1745     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be deployed")
1746     scenario_deploy_parser.add_argument("name", action="store", help="name of the instance")
1747     scenario_deploy_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1748     scenario_deploy_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1749     scenario_deploy_parser.add_argument("--description", action="store", help="description of the instance")
1750     scenario_deploy_parser.set_defaults(func=scenario_deploy)
1751     
1752     scenario_deploy_parser = subparsers.add_parser('scenario-verify', help="verifies if a scenario can be deployed (deploys it and deletes it)")
1753     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be verified")
1754     scenario_deploy_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1755     scenario_deploy_parser.set_defaults(func=scenario_verify)
1756     
1757     instance_scenario_create_parser = subparsers.add_parser('instance-scenario-create', parents=[parent_parser], help="deploys a scenario")
1758     instance_scenario_create_parser.add_argument("file", nargs='?', help="descriptor of the instance. Must be a file or yaml/json text")
1759     instance_scenario_create_parser.add_argument("--scenario", action="store", help="name or uuid of the scenario to be deployed")
1760     instance_scenario_create_parser.add_argument("--name", action="store", help="name of the instance")
1761     instance_scenario_create_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1762     instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1763     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")
1764     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")
1765     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")
1766     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")
1767     instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
1768     instance_scenario_create_parser.set_defaults(func=instance_create)
1769
1770     instance_scenario_list_parser = subparsers.add_parser('instance-scenario-list', parents=[parent_parser], help="lists information about a scenario instance")
1771     instance_scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario instance")
1772     instance_scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all instance-scenarios, not only the owned")
1773     instance_scenario_list_parser.set_defaults(func=instance_scenario_list)
1774
1775     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)")
1776     instance_scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario instance to be deleted")
1777     instance_scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1778     instance_scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1779     instance_scenario_delete_parser.set_defaults(func=instance_scenario_delete)
1780     
1781     instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
1782     instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1783     instance_scenario_action_parser.add_argument("action", action="store", type=str, \
1784             choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console", "add_public_key","vdu-scaling"],\
1785             help="action to send")
1786     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}]'")
1787     instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
1788     instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
1789     instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
1790
1791     action_parser = subparsers.add_parser('action-list', parents=[parent_parser], help="get action over an instance status")
1792     action_parser.add_argument("id", nargs='?', action="store", help="action id")
1793     action_parser.add_argument("--instance", action="store", help="fitler by this instance_id")
1794     action_parser.add_argument("--all", action="store", help="Not filter by tenant")
1795     action_parser.set_defaults(func=get_action)
1796
1797     #instance_scenario_status_parser = subparsers.add_parser('instance-scenario-status', help="show the status of a scenario instance")
1798     #instance_scenario_status_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1799     #instance_scenario_status_parser.set_defaults(func=instance_scenario_status)
1800     
1801     tenant_create_parser = subparsers.add_parser('tenant-create', parents=[parent_parser], help="creates a new tenant")
1802     tenant_create_parser.add_argument("name", action="store", help="name for the tenant")
1803     tenant_create_parser.add_argument("--description", action="store", help="description of the tenant")
1804     tenant_create_parser.set_defaults(func=tenant_create)
1805
1806     tenant_delete_parser = subparsers.add_parser('tenant-delete', parents=[parent_parser], help="deletes a tenant from the catalogue")
1807     tenant_delete_parser.add_argument("name", action="store", help="name or uuid of the tenant to be deleted")
1808     tenant_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1809     tenant_delete_parser.set_defaults(func=tenant_delete)
1810
1811     tenant_list_parser = subparsers.add_parser('tenant-list', parents=[parent_parser], help="lists information about a tenant")
1812     tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
1813     tenant_list_parser.set_defaults(func=tenant_list)
1814
1815     element_edit_parser = subparsers.add_parser('tenant-edit', parents=[parent_parser], help="edits one tenant")
1816     element_edit_parser.add_argument("name", help="name or uuid of the tenant")
1817     element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1818     element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1819     element_edit_parser.set_defaults(func=element_edit, element='tenants')
1820
1821     datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
1822     datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
1823     datacenter_create_parser.add_argument("url", action="store", help="url for the datacenter")
1824     datacenter_create_parser.add_argument("--url_admin", action="store", help="url for administration for the datacenter")
1825     datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
1826     datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1827     datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
1828     datacenter_create_parser.add_argument("--sdn-controller", action="store", help="Name or uuid of the SDN controller to be used", dest='sdn_controller')
1829     datacenter_create_parser.set_defaults(func=datacenter_create)
1830
1831     datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
1832     datacenter_delete_parser.add_argument("name", action="store", help="name or uuid of the datacenter to be deleted")
1833     datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1834     datacenter_delete_parser.set_defaults(func=datacenter_delete)
1835
1836     datacenter_edit_parser = subparsers.add_parser('datacenter-edit', parents=[parent_parser], help="Edit datacenter")
1837     datacenter_edit_parser.add_argument("name", help="name or uuid of the datacenter")
1838     datacenter_edit_parser.add_argument("--file", help="json/yaml text or file with the changes").completer = FilesCompleter
1839     datacenter_edit_parser.add_argument("--sdn-controller", action="store",
1840                                           help="Name or uuid of the SDN controller to be used. Specify 'null' to clear entry", dest='sdn_controller')
1841     datacenter_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
1842     datacenter_edit_parser.set_defaults(func=datacenter_edit)
1843
1844     datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
1845     datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
1846     datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
1847     datacenter_list_parser.set_defaults(func=datacenter_list)
1848
1849     datacenter_attach_parser = subparsers.add_parser('datacenter-attach', parents=[parent_parser], help="associates a datacenter to the operating tenant")
1850     datacenter_attach_parser.add_argument("name", help="name or uuid of the datacenter")
1851     datacenter_attach_parser.add_argument('--vim-tenant-id', action='store', help="specify a datacenter tenant to use. A new one is created by default")
1852     datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1853     datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1854     datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1855     datacenter_attach_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1856     datacenter_attach_parser.set_defaults(func=datacenter_attach)
1857
1858     datacenter_edit_vim_tenant_parser = subparsers.add_parser('datacenter-edit-vim-tenant', parents=[parent_parser],
1859                                                      help="Edit the association of a datacenter to the operating tenant")
1860     datacenter_edit_vim_tenant_parser.add_argument("name", help="name or uuid of the datacenter")
1861     datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-id', action='store',
1862                                           help="specify a datacenter tenant to use. A new one is created by default")
1863     datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1864     datacenter_edit_vim_tenant_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1865     datacenter_edit_vim_tenant_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1866     datacenter_edit_vim_tenant_parser.add_argument("--config", action="store",
1867                                           help="aditional configuration in json/yaml format")
1868     datacenter_edit_vim_tenant_parser.set_defaults(func=datacenter_edit_vim_tenant)
1869
1870     datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
1871     datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
1872     datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
1873     datacenter_detach_parser.set_defaults(func=datacenter_detach)
1874
1875     #=======================datacenter_sdn_port_mapping_xxx section=======================
1876     #datacenter_sdn_port_mapping_set
1877     datacenter_sdn_port_mapping_set_parser = subparsers.add_parser('datacenter-sdn-port-mapping-set',
1878                                                                    parents=[parent_parser],
1879                                                                    help="Load a file with the mapping of physical ports "
1880                                                                         "and the ports of the dataplaneswitch controlled "
1881                                                                         "by a datacenter")
1882     datacenter_sdn_port_mapping_set_parser.add_argument("name", action="store", help="specifies the datacenter")
1883     datacenter_sdn_port_mapping_set_parser.add_argument("file",
1884                                                         help="json/yaml text or file with the port mapping").completer = FilesCompleter
1885     datacenter_sdn_port_mapping_set_parser.add_argument("-f", "--force", action="store_true",
1886                                                           help="forces overwriting without asking")
1887     datacenter_sdn_port_mapping_set_parser.set_defaults(func=datacenter_sdn_port_mapping_set)
1888
1889     #datacenter_sdn_port_mapping_list
1890     datacenter_sdn_port_mapping_list_parser = subparsers.add_parser('datacenter-sdn-port-mapping-list',
1891                                                                     parents=[parent_parser],
1892                                                                     help="Show the SDN port mapping in a datacenter")
1893     datacenter_sdn_port_mapping_list_parser.add_argument("name", action="store", help="specifies the datacenter")
1894     datacenter_sdn_port_mapping_list_parser.set_defaults(func=datacenter_sdn_port_mapping_list)
1895
1896     # datacenter_sdn_port_mapping_clear
1897     datacenter_sdn_port_mapping_clear_parser = subparsers.add_parser('datacenter-sdn-port-mapping-clear',
1898                                                                     parents=[parent_parser],
1899                                                                     help="Clean the the SDN port mapping in a datacenter")
1900     datacenter_sdn_port_mapping_clear_parser.add_argument("name", action="store",
1901                                                          help="specifies the datacenter")
1902     datacenter_sdn_port_mapping_clear_parser.add_argument("-f", "--force", action="store_true",
1903                                               help="forces clearing without asking")
1904     datacenter_sdn_port_mapping_clear_parser.set_defaults(func=datacenter_sdn_port_mapping_clear)
1905     # =======================
1906
1907     # =======================sdn_controller_xxx section=======================
1908     # sdn_controller_create
1909     sdn_controller_create_parser = subparsers.add_parser('sdn-controller-create', parents=[parent_parser],
1910                                                         help="Creates an SDN controller entity within RO")
1911     sdn_controller_create_parser.add_argument("name", help="name of the SDN controller")
1912     sdn_controller_create_parser.add_argument("--description", action="store", help="description of the SDN controller")
1913     sdn_controller_create_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
1914     sdn_controller_create_parser.add_argument("--port", action="store", help="Port of the SDN controller")
1915     sdn_controller_create_parser.add_argument("--dpid", action="store",
1916                                              help="DPID of the dataplane switch controlled by this SDN controller")
1917     sdn_controller_create_parser.add_argument("--type", action="store",
1918                                              help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
1919     sdn_controller_create_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
1920     sdn_controller_create_parser.add_argument("--passwd", action="store", dest='password',
1921                                              help="password credentials for the SDN controller")
1922     sdn_controller_create_parser.set_defaults(func=sdn_controller_create)
1923
1924     # sdn_controller_edit
1925     sdn_controller_edit_parser = subparsers.add_parser('sdn-controller-edit', parents=[parent_parser],
1926                                                         help="Update one or more options of a SDN controller")
1927     sdn_controller_edit_parser.add_argument("name", help="name or uuid of the SDN controller", )
1928     sdn_controller_edit_parser.add_argument("--name", action="store", help="Update the name of the SDN controller",
1929                                               dest='new_name')
1930     sdn_controller_edit_parser.add_argument("--description", action="store", help="description of the SDN controller")
1931     sdn_controller_edit_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
1932     sdn_controller_edit_parser.add_argument("--port", action="store", help="Port of the SDN controller")
1933     sdn_controller_edit_parser.add_argument("--dpid", action="store",
1934                                              help="DPID of the dataplane switch controlled by this SDN controller")
1935     sdn_controller_edit_parser.add_argument("--type", action="store",
1936                                              help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
1937     sdn_controller_edit_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
1938     sdn_controller_edit_parser.add_argument("--password", action="store",
1939                                              help="password credentials for the SDN controller", dest='password')
1940     sdn_controller_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
1941     #TODO: include option --file
1942     sdn_controller_edit_parser.set_defaults(func=sdn_controller_edit)
1943
1944     #sdn_controller_list
1945     sdn_controller_list_parser = subparsers.add_parser('sdn-controller-list',
1946                                                                     parents=[parent_parser],
1947                                                                     help="List the SDN controllers")
1948     sdn_controller_list_parser.add_argument("name", nargs='?', help="name or uuid of the SDN controller")
1949     sdn_controller_list_parser.set_defaults(func=sdn_controller_list)
1950
1951     # sdn_controller_delete
1952     sdn_controller_delete_parser = subparsers.add_parser('sdn-controller-delete',
1953                                                                     parents=[parent_parser],
1954                                                                     help="Delete the the SDN controller")
1955     sdn_controller_delete_parser.add_argument("name", help="name or uuid of the SDN controller")
1956     sdn_controller_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1957     sdn_controller_delete_parser.set_defaults(func=sdn_controller_delete)
1958     # =======================
1959
1960     action_dict={'net-update': 'retrieves external networks from datacenter',
1961                  'net-edit': 'edits an external network',
1962                  'net-delete': 'deletes an external network',
1963                  'net-list': 'lists external networks from a datacenter'
1964                  }
1965     for item in action_dict:
1966         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1967         datacenter_action_parser.add_argument("datacenter", help="name or uuid of the datacenter")
1968         if item=='net-edit' or item=='net-delete':
1969             datacenter_action_parser.add_argument("net", help="name or uuid of the datacenter net")
1970         if item=='net-edit':
1971             datacenter_action_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1972         if item!='net-list':
1973             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1974         datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
1975
1976
1977     action_dict={'netmap-import': 'create network senario netmap base on the datacenter networks',
1978                  'netmap-create': 'create a new network senario netmap',
1979                  'netmap-edit':   'edit name of a network senario netmap',
1980                  'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
1981                  'netmap-list':   'list/show network scenario netmaps'
1982                  }
1983     for item in action_dict:
1984         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1985         datacenter_action_parser.add_argument("--datacenter", help="name or uuid of the datacenter")
1986         #if item=='net-add':
1987         #    datacenter_action_parser.add_argument("net", help="name of the network")
1988         if item=='netmap-delete':
1989             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to delete")
1990             datacenter_action_parser.add_argument("--all", action="store_true", help="delete all netmap of this datacenter")
1991             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1992         if item=='netmap-edit':
1993             datacenter_action_parser.add_argument("netmap", help="name or uuid of the datacenter netmap do edit")
1994             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file with the changes").completer = FilesCompleter
1995             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap")
1996             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1997             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1998         if item=='netmap-list':
1999             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to show")
2000         if item=='netmap-create':
2001             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file descriptor with the changes").completer = FilesCompleter
2002             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
2003             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
2004             datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
2005         if item=='netmap-import':
2006             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
2007         datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)
2008
2009     # =======================vim_net_sdn_xxx section=======================
2010     # vim_net_sdn_attach
2011     vim_net_sdn_attach_parser = subparsers.add_parser('vim-net-sdn-attach',
2012                                                       parents=[parent_parser],
2013                                                       help="Specify the port to access to an external network using SDN")
2014     vim_net_sdn_attach_parser.add_argument("vim_net", action="store",
2015                                                 help="Name/id of the network in the vim that will be used to connect to the external network")
2016     vim_net_sdn_attach_parser.add_argument("port", action="store", help="Specifies the port in the dataplane switch to access to the external network")
2017     vim_net_sdn_attach_parser.add_argument("--vlan", action="store", help="Specifies the vlan (if any) to use in the defined port")
2018     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")
2019     vim_net_sdn_attach_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2020     vim_net_sdn_attach_parser.set_defaults(func=vim_net_sdn_attach)
2021
2022     # vim_net_sdn_detach
2023     vim_net_sdn_detach_parser = subparsers.add_parser('vim-net-sdn-detach',
2024                                                            parents=[parent_parser],
2025                                                            help="Remove the port information to access to an external network using SDN")
2026
2027     vim_net_sdn_detach_parser.add_argument("vim_net", action="store", help="Name/id of the vim network")
2028     vim_net_sdn_detach_parser.add_argument("--id", action="store",help="Specify the uuid of the external ports from this network to be detached")
2029     vim_net_sdn_detach_parser.add_argument("--all", action="store_true", help="Detach all external ports from this network")
2030     vim_net_sdn_detach_parser.add_argument("-f", "--force", action="store_true", help="forces clearing without asking")
2031     vim_net_sdn_detach_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2032     vim_net_sdn_detach_parser.set_defaults(func=vim_net_sdn_detach)
2033     # =======================
2034
2035     for item in ("network", "tenant", "image"):
2036         if item=="network":
2037             command_name = 'vim-net'
2038         else:
2039             command_name = 'vim-'+item
2040         vim_item_list_parser = subparsers.add_parser(command_name + '-list', parents=[parent_parser], help="list the vim " + item + "s")
2041         vim_item_list_parser.add_argument("name", nargs='?', help="name or uuid of the " + item + "s")
2042         vim_item_list_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2043         vim_item_list_parser.set_defaults(func=vim_action, item=item, action="list")
2044
2045         vim_item_del_parser = subparsers.add_parser(command_name + '-delete', parents=[parent_parser], help="list the vim " + item + "s")
2046         vim_item_del_parser.add_argument("name", help="name or uuid of the " + item + "s")
2047         vim_item_del_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2048         vim_item_del_parser.set_defaults(func=vim_action, item=item, action="delete")
2049
2050         if item == "network" or item == "tenant":
2051             vim_item_create_parser = subparsers.add_parser(command_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
2052             vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the %s. Must be a file or yaml/json text" % item).completer = FilesCompleter
2053             vim_item_create_parser.add_argument("--name", action="store", help="name of the %s" % item  )
2054             vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2055             if item=="network":
2056                 vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
2057                 vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
2058                 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>'")
2059             else:
2060                 vim_item_create_parser.add_argument("--description", action="store", help="description of the %s" % item)
2061             vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
2062
2063     argcomplete.autocomplete(main_parser)
2064     
2065     try:
2066         args = main_parser.parse_args()
2067         #logging info
2068         level = logging.CRITICAL
2069         streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
2070         if "debug" in args and args.debug:
2071             level = logging.DEBUG
2072         logging.basicConfig(format=streamformat, level= level)
2073         logger = logging.getLogger('mano')
2074         logger.setLevel(level)
2075         result = args.func(args)
2076         if result == None:
2077             result = 0
2078         #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
2079     except (requests.exceptions.ConnectionError):
2080         print "Connection error: not possible to contact OPENMANO-SERVER (openmanod)"
2081         result = -2
2082     except (KeyboardInterrupt):
2083         print 'Exiting openmano'
2084         result = -3
2085     except (SystemExit, ArgumentParserError):
2086         result = -4
2087     except OpenmanoCLIError as e:
2088         print str(e)
2089         result = -5
2090     
2091     #print result
2092     exit(result)
2093