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