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