fix an issue at openmano client for tenant-edit
[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 global mano_host
1466 global mano_port
1467 global mano_tenant
1468
1469 if __name__=="__main__":
1470     
1471     mano_tenant = os.getenv('OPENMANO_TENANT', None)
1472     mano_host = os.getenv('OPENMANO_HOST',"localhost")
1473     mano_port = os.getenv('OPENMANO_PORT',"9090")
1474     mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
1475     
1476     main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
1477     main_parser.add_argument('--version', action='version', version='%(prog)s ' + __version__ )
1478     
1479     subparsers = main_parser.add_subparsers(help='commands')
1480     
1481     parent_parser = argparse.ArgumentParser(add_help=False)
1482     parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
1483     parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1484
1485     config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
1486     config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
1487     config_parser.set_defaults(func=config)
1488
1489     vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
1490     vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
1491     vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1492     vnf_create_parser.add_argument("--description", action="store", help="description of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1493     vnf_create_parser.add_argument("--image-path", action="store",  help="change image path locations (overwritten)")
1494     vnf_create_parser.add_argument("--image-name", action="store",  help="change image name (overwritten)")
1495     vnf_create_parser.add_argument("--image-checksum", action="store",  help="change image checksum (overwritten)")
1496     vnf_create_parser.set_defaults(func=vnf_create)
1497
1498     vnf_list_parser = subparsers.add_parser('vnf-list', parents=[parent_parser], help="lists information about a vnf")
1499     vnf_list_parser.add_argument("name", nargs='?', help="name of the VNF")
1500     vnf_list_parser.add_argument("-a", "--all", action="store_true", help="shows all vnfs, not only the owned or public ones")
1501     #vnf_list_parser.add_argument('--descriptor', help="prints the VNF descriptor", action="store_true")
1502     vnf_list_parser.set_defaults(func=vnf_list)
1503     
1504     vnf_delete_parser = subparsers.add_parser('vnf-delete', parents=[parent_parser], help="deletes a vnf from the catalogue")
1505     vnf_delete_parser.add_argument("name", action="store", help="name or uuid of the VNF to be deleted")
1506     vnf_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1507     vnf_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1508     vnf_delete_parser.set_defaults(func=vnf_delete)
1509     
1510     scenario_create_parser = subparsers.add_parser('scenario-create', parents=[parent_parser], help="adds a scenario into the OPENMANO DB")
1511     scenario_create_parser.add_argument("file", action="store", help="location of the YAML file describing the scenario").completer = FilesCompleter
1512     scenario_create_parser.add_argument("--name", action="store", help="name of the scenario (if it exists in the YAML scenario, it is overwritten)")
1513     scenario_create_parser.add_argument("--description", action="store", help="description of the scenario (if it exists in the YAML scenario, it is overwritten)")
1514     scenario_create_parser.set_defaults(func=scenario_create)
1515
1516     scenario_list_parser = subparsers.add_parser('scenario-list', parents=[parent_parser], help="lists information about a scenario")
1517     scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario")
1518     #scenario_list_parser.add_argument('--descriptor', help="prints the scenario descriptor", action="store_true")
1519     scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all scenarios, not only the owned or public ones")
1520     scenario_list_parser.set_defaults(func=scenario_list)
1521     
1522     scenario_delete_parser = subparsers.add_parser('scenario-delete', parents=[parent_parser], help="deletes a scenario from the OPENMANO DB")
1523     scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario to be deleted")
1524     scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1525     scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1526     scenario_delete_parser.set_defaults(func=scenario_delete)
1527
1528     scenario_deploy_parser = subparsers.add_parser('scenario-deploy', parents=[parent_parser], help="deploys a scenario")
1529     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be deployed")
1530     scenario_deploy_parser.add_argument("name", action="store", help="name of the instance")
1531     scenario_deploy_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1532     scenario_deploy_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1533     scenario_deploy_parser.add_argument("--description", action="store", help="description of the instance")
1534     scenario_deploy_parser.set_defaults(func=scenario_deploy)
1535     
1536     scenario_deploy_parser = subparsers.add_parser('scenario-verify', help="verifies if a scenario can be deployed (deploys it and deletes it)")
1537     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be verified")
1538     scenario_deploy_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1539     scenario_deploy_parser.set_defaults(func=scenario_verify)
1540     
1541     instance_scenario_create_parser = subparsers.add_parser('instance-scenario-create', parents=[parent_parser], help="deploys a scenario")
1542     instance_scenario_create_parser.add_argument("file", nargs='?', help="descriptor of the instance. Must be a file or yaml/json text")
1543     instance_scenario_create_parser.add_argument("--scenario", action="store", help="name or uuid of the scenario to be deployed")
1544     instance_scenario_create_parser.add_argument("--name", action="store", help="name of the instance")
1545     instance_scenario_create_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1546     instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1547     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")
1548     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")
1549     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")
1550     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")
1551     instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
1552     instance_scenario_create_parser.set_defaults(func=instance_create)
1553
1554     instance_scenario_list_parser = subparsers.add_parser('instance-scenario-list', parents=[parent_parser], help="lists information about a scenario instance")
1555     instance_scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario instance")
1556     instance_scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all instance-scenarios, not only the owned")
1557     instance_scenario_list_parser.set_defaults(func=instance_scenario_list)
1558
1559     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)")
1560     instance_scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario instance to be deleted")
1561     instance_scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1562     instance_scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1563     instance_scenario_delete_parser.set_defaults(func=instance_scenario_delete)
1564     
1565     instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
1566     instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1567     instance_scenario_action_parser.add_argument("action", action="store", type=str, \
1568             choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console"],\
1569             help="action to send")
1570     instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console type (novnc, ...), reboot type (TODO)")
1571     instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
1572     instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
1573     instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
1574
1575     #instance_scenario_status_parser = subparsers.add_parser('instance-scenario-status', help="show the status of a scenario instance")
1576     #instance_scenario_status_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1577     #instance_scenario_status_parser.set_defaults(func=instance_scenario_status)
1578     
1579     tenant_create_parser = subparsers.add_parser('tenant-create', parents=[parent_parser], help="creates a new tenant")
1580     tenant_create_parser.add_argument("name", action="store", help="name for the tenant")
1581     tenant_create_parser.add_argument("--description", action="store", help="description of the tenant")
1582     tenant_create_parser.set_defaults(func=tenant_create)
1583
1584     tenant_delete_parser = subparsers.add_parser('tenant-delete', parents=[parent_parser], help="deletes a tenant from the catalogue")
1585     tenant_delete_parser.add_argument("name", action="store", help="name or uuid of the tenant to be deleted")
1586     tenant_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1587     tenant_delete_parser.set_defaults(func=tenant_delete)
1588
1589     tenant_list_parser = subparsers.add_parser('tenant-list', parents=[parent_parser], help="lists information about a tenant")
1590     tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
1591     tenant_list_parser.set_defaults(func=tenant_list)
1592
1593     element_edit_parser = subparsers.add_parser('tenant-edit', parents=[parent_parser], help="edits one tenant")
1594     element_edit_parser.add_argument("name", help="name or uuid of the tenant")
1595     element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1596     element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1597     element_edit_parser.set_defaults(func=element_edit, element='tenants')
1598
1599     datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
1600     datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
1601     datacenter_create_parser.add_argument("url", action="store", help="url for the datacenter")
1602     datacenter_create_parser.add_argument("--url_admin", action="store", help="url for administration for the datacenter")
1603     datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
1604     datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1605     datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
1606     datacenter_create_parser.add_argument("--sdn-controller", action="store", help="Name or uuid of the SDN controller to be used", dest='sdn_controller')
1607     datacenter_create_parser.set_defaults(func=datacenter_create)
1608
1609     datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
1610     datacenter_delete_parser.add_argument("name", action="store", help="name or uuid of the datacenter to be deleted")
1611     datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1612     datacenter_delete_parser.set_defaults(func=datacenter_delete)
1613
1614     datacenter_edit_parser = subparsers.add_parser('datacenter-edit', parents=[parent_parser], help="Edit datacenter")
1615     datacenter_edit_parser.add_argument("name", help="name or uuid of the datacenter")
1616     datacenter_edit_parser.add_argument("--file", help="json/yaml text or file with the changes").completer = FilesCompleter
1617     datacenter_edit_parser.add_argument("--sdn-controller", action="store",
1618                                           help="Name or uuid of the SDN controller to be used. Specify 'null' to clear entry", dest='sdn_controller')
1619     datacenter_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
1620     datacenter_edit_parser.set_defaults(func=datacenter_edit)
1621
1622     datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
1623     datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
1624     datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
1625     datacenter_list_parser.set_defaults(func=datacenter_list)
1626
1627     datacenter_attach_parser = subparsers.add_parser('datacenter-attach', parents=[parent_parser], help="associates a datacenter to the operating tenant")
1628     datacenter_attach_parser.add_argument("name", help="name or uuid of the datacenter")
1629     datacenter_attach_parser.add_argument('--vim-tenant-id', action='store', help="specify a datacenter tenant to use. A new one is created by default")
1630     datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1631     datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1632     datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1633     datacenter_attach_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1634     datacenter_attach_parser.set_defaults(func=datacenter_attach)
1635
1636     datacenter_edit_vim_tenant_parser = subparsers.add_parser('datacenter-edit-vim-tenant', parents=[parent_parser],
1637                                                      help="Edit the association of a datacenter to the operating tenant")
1638     datacenter_edit_vim_tenant_parser.add_argument("name", help="name or uuid of the datacenter")
1639     datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-id', action='store',
1640                                           help="specify a datacenter tenant to use. A new one is created by default")
1641     datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1642     datacenter_edit_vim_tenant_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1643     datacenter_edit_vim_tenant_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1644     datacenter_edit_vim_tenant_parser.add_argument("--config", action="store",
1645                                           help="aditional configuration in json/yaml format")
1646     datacenter_edit_vim_tenant_parser.set_defaults(func=datacenter_edit_vim_tenant)
1647
1648     datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
1649     datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
1650     datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
1651     datacenter_detach_parser.set_defaults(func=datacenter_detach)
1652
1653     #=======================datacenter_sdn_port_mapping_xxx section=======================
1654     #datacenter_sdn_port_mapping_set
1655     datacenter_sdn_port_mapping_set_parser = subparsers.add_parser('datacenter-sdn-port-mapping-set',
1656                                                                    parents=[parent_parser],
1657                                                                    help="Load a file with the mapping of physical ports "
1658                                                                         "and the ports of the dataplaneswitch controlled "
1659                                                                         "by a datacenter")
1660     datacenter_sdn_port_mapping_set_parser.add_argument("name", action="store", help="specifies the datacenter")
1661     datacenter_sdn_port_mapping_set_parser.add_argument("file",
1662                                                         help="json/yaml text or file with the port mapping").completer = FilesCompleter
1663     datacenter_sdn_port_mapping_set_parser.add_argument("-f", "--force", action="store_true",
1664                                                           help="forces overwriting without asking")
1665     datacenter_sdn_port_mapping_set_parser.set_defaults(func=datacenter_sdn_port_mapping_set)
1666
1667     #datacenter_sdn_port_mapping_list
1668     datacenter_sdn_port_mapping_list_parser = subparsers.add_parser('datacenter-sdn-port-mapping-list',
1669                                                                     parents=[parent_parser],
1670                                                                     help="Show the SDN port mapping in a datacenter")
1671     datacenter_sdn_port_mapping_list_parser.add_argument("name", action="store", help="specifies the datacenter")
1672     datacenter_sdn_port_mapping_list_parser.set_defaults(func=datacenter_sdn_port_mapping_list)
1673
1674     # datacenter_sdn_port_mapping_clear
1675     datacenter_sdn_port_mapping_clear_parser = subparsers.add_parser('datacenter-sdn-port-mapping-clear',
1676                                                                     parents=[parent_parser],
1677                                                                     help="Clean the the SDN port mapping in a datacenter")
1678     datacenter_sdn_port_mapping_clear_parser.add_argument("name", action="store",
1679                                                          help="specifies the datacenter")
1680     datacenter_sdn_port_mapping_clear_parser.add_argument("-f", "--force", action="store_true",
1681                                               help="forces clearing without asking")
1682     datacenter_sdn_port_mapping_clear_parser.set_defaults(func=datacenter_sdn_port_mapping_clear)
1683     # =======================
1684
1685     # =======================sdn_controller_xxx section=======================
1686     # sdn_controller_create
1687     sdn_controller_create_parser = subparsers.add_parser('sdn-controller-create', parents=[parent_parser],
1688                                                         help="Creates an SDN controller entity within RO")
1689     sdn_controller_create_parser.add_argument("name", help="name of the SDN controller")
1690     sdn_controller_create_parser.add_argument("--description", action="store", help="description of the SDN controller")
1691     sdn_controller_create_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
1692     sdn_controller_create_parser.add_argument("--port", action="store", help="Port of the SDN controller")
1693     sdn_controller_create_parser.add_argument("--dpid", action="store",
1694                                              help="DPID of the dataplane switch controlled by this SDN controller")
1695     sdn_controller_create_parser.add_argument("--type", action="store",
1696                                              help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
1697     sdn_controller_create_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
1698     sdn_controller_create_parser.add_argument("--passwd", action="store", dest='password',
1699                                              help="password credentials for the SDN controller")
1700     sdn_controller_create_parser.set_defaults(func=sdn_controller_create)
1701
1702     # sdn_controller_edit
1703     sdn_controller_edit_parser = subparsers.add_parser('sdn-controller-edit', parents=[parent_parser],
1704                                                         help="Update one or more options of a SDN controller")
1705     sdn_controller_edit_parser.add_argument("name", help="name or uuid of the SDN controller", )
1706     sdn_controller_edit_parser.add_argument("--name", action="store", help="Update the name of the SDN controller",
1707                                               dest='new_name')
1708     sdn_controller_edit_parser.add_argument("--description", action="store", help="description of the SDN controller")
1709     sdn_controller_edit_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
1710     sdn_controller_edit_parser.add_argument("--port", action="store", help="Port of the SDN controller")
1711     sdn_controller_edit_parser.add_argument("--dpid", action="store",
1712                                              help="DPID of the dataplane switch controlled by this SDN controller")
1713     sdn_controller_edit_parser.add_argument("--type", action="store",
1714                                              help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
1715     sdn_controller_edit_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
1716     sdn_controller_edit_parser.add_argument("--password", action="store",
1717                                              help="password credentials for the SDN controller", dest='password')
1718     sdn_controller_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
1719     #TODO: include option --file
1720     sdn_controller_edit_parser.set_defaults(func=sdn_controller_edit)
1721
1722     #sdn_controller_list
1723     sdn_controller_list_parser = subparsers.add_parser('sdn-controller-list',
1724                                                                     parents=[parent_parser],
1725                                                                     help="List the SDN controllers")
1726     sdn_controller_list_parser.add_argument("name", nargs='?', help="name or uuid of the SDN controller")
1727     sdn_controller_list_parser.set_defaults(func=sdn_controller_list)
1728
1729     # sdn_controller_delete
1730     sdn_controller_delete_parser = subparsers.add_parser('sdn-controller-delete',
1731                                                                     parents=[parent_parser],
1732                                                                     help="Delete the the SDN controller")
1733     sdn_controller_delete_parser.add_argument("name", help="name or uuid of the SDN controller")
1734     sdn_controller_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1735     sdn_controller_delete_parser.set_defaults(func=sdn_controller_delete)
1736     # =======================
1737
1738     action_dict={'net-update': 'retrieves external networks from datacenter',
1739                  'net-edit': 'edits an external network',
1740                  'net-delete': 'deletes an external network',
1741                  'net-list': 'lists external networks from a datacenter'
1742                  }
1743     for item in action_dict:
1744         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1745         datacenter_action_parser.add_argument("datacenter", help="name or uuid of the datacenter")
1746         if item=='net-edit' or item=='net-delete':
1747             datacenter_action_parser.add_argument("net", help="name or uuid of the datacenter net")
1748         if item=='net-edit':
1749             datacenter_action_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1750         if item!='net-list':
1751             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1752         datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
1753
1754
1755     action_dict={'netmap-import': 'create network senario netmap base on the datacenter networks',
1756                  'netmap-create': 'create a new network senario netmap',
1757                  'netmap-edit':   'edit name of a network senario netmap',
1758                  'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
1759                  'netmap-list':   'list/show network scenario netmaps'
1760                  }
1761     for item in action_dict:
1762         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1763         datacenter_action_parser.add_argument("--datacenter", help="name or uuid of the datacenter")
1764         #if item=='net-add':
1765         #    datacenter_action_parser.add_argument("net", help="name of the network")
1766         if item=='netmap-delete':
1767             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to delete")
1768             datacenter_action_parser.add_argument("--all", action="store_true", help="delete all netmap of this datacenter")
1769             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1770         if item=='netmap-edit':
1771             datacenter_action_parser.add_argument("netmap", help="name or uuid of the datacenter netmap do edit")
1772             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file with the changes").completer = FilesCompleter
1773             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap")
1774             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1775             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1776         if item=='netmap-list':
1777             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to show")
1778         if item=='netmap-create':
1779             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file descriptor with the changes").completer = FilesCompleter
1780             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
1781             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1782             datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
1783         if item=='netmap-import':
1784             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1785         datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)
1786     
1787     for item in ("network", "tenant", "image"):
1788         if item=="network":
1789             commnad_name = 'vim-net'
1790         else:
1791             commnad_name = 'vim-'+item
1792         vim_item_list_parser = subparsers.add_parser(commnad_name + '-list', parents=[parent_parser], help="list the vim " + item + "s")
1793         vim_item_list_parser.add_argument("name", nargs='?', help="name or uuid of the " + item + "s")
1794         vim_item_list_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1795         vim_item_list_parser.set_defaults(func=vim_action, item=item, action="list")
1796
1797         vim_item_del_parser = subparsers.add_parser(commnad_name + '-delete', parents=[parent_parser], help="list the vim " + item + "s")
1798         vim_item_del_parser.add_argument("name", help="name or uuid of the " + item + "s")
1799         vim_item_del_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1800         vim_item_del_parser.set_defaults(func=vim_action, item=item, action="delete")
1801
1802         if item == "network" or item == "tenant":
1803             vim_item_create_parser = subparsers.add_parser(commnad_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
1804             vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the %s. Must be a file or yaml/json text" % item).completer = FilesCompleter
1805             vim_item_create_parser.add_argument("--name", action="store", help="name of the %s" % item  )
1806             vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1807             if item=="network":
1808                 vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
1809                 vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
1810                 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>'")
1811             else:
1812                 vim_item_create_parser.add_argument("--description", action="store", help="description of the %s" % item)
1813             vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
1814
1815     argcomplete.autocomplete(main_parser)
1816     
1817     try:
1818         args = main_parser.parse_args()
1819         #logging info
1820         level = logging.CRITICAL
1821         streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
1822         if "debug" in args and args.debug:
1823             level = logging.DEBUG
1824         logging.basicConfig(format=streamformat, level= level)
1825         logger = logging.getLogger('mano')
1826         logger.setLevel(level)
1827         result = args.func(args)
1828         if result == None:
1829             result = 0
1830         #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
1831     except (requests.exceptions.ConnectionError):
1832         print "Connection error: not possible to contact OPENMANO-SERVER (openmanod)"
1833         result = -2
1834     except (KeyboardInterrupt):
1835         print 'Exiting openmano'
1836         result = -3
1837     except (SystemExit, ArgumentParserError):
1838         result = -4
1839     except OpenmanoCLIError as e:
1840         print str(e)
1841         result = -5
1842     
1843     #print result
1844     exit(result)
1845