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