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