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