(Bug 279) openmano client v0.4.14: obtain tenant id from name on all commands
[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.14-r521"
32 version_date = "May 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     tenant = _get_tenant()
560     headers_req = {'content-type': 'application/json'}
561     action = {}
562     action["verify"] = {}
563     action["verify"]["instance_name"] = "scen-verify-return5"
564     payload_req = json.dumps(action, indent=4)
565     #print payload_req
566
567     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, tenant, args.scenario)
568     logger.debug("openmano request: %s", payload_req)
569     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
570     logger.debug("openmano response: %s", mano_response.text )
571     
572     result = 0 if mano_response.status_code==200 else mano_response.status_code
573     content = mano_response.json()
574     #print json.dumps(content, indent=4)
575     if mano_response.status_code == 200:
576         print content['result']
577     else:
578         print content['error']['description']
579     return result
580
581 def instance_create(args):
582     tenant = _get_tenant()
583     headers_req = {'content-type': 'application/yaml'}
584     myInstance={"instance": {}, "schema_version": "0.1"}
585     if args.file:
586         instance_dict = _load_file_or_yaml(args.file)
587         if "instance" not in instance_dict:
588             myInstance = {"instance": instance_dict, "schema_version": "0.1"}
589         else:
590             myInstance = instance_dict
591     if args.name:
592         myInstance["instance"]['name'] = args.name
593     if args.description:
594         myInstance["instance"]['description'] = args.description
595     if args.nostart:
596         myInstance["instance"]['action'] = "reserve"
597     #datacenter
598     datacenter = myInstance["instance"].get("datacenter")
599     if args.datacenter != None:
600         datacenter = args.datacenter
601     myInstance["instance"]["datacenter"] = _get_datacenter(datacenter, tenant)
602     #scenario
603     scenario = myInstance["instance"].get("scenario")
604     if args.scenario != None:
605         scenario = args.scenario
606     if not scenario:
607         print "you must provide a scenario in the file descriptor or with --scenario"
608         return -1
609     myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
610     if args.netmap_use:
611         if "networks" not in myInstance["instance"]:
612             myInstance["instance"]["networks"] = {}
613         for net in args.netmap_use:
614             net_comma_list = net.split(",")
615             for net_comma in net_comma_list:
616                 net_tuple = net_comma.split("=")
617                 if len(net_tuple) != 2:
618                     print "error at netmap-use. Expected net-scenario=net-datacenter. (%s)?" % net_comma
619                     return
620                 net_scenario   = net_tuple[0].strip()
621                 net_datacenter = net_tuple[1].strip()
622                 if net_scenario not in myInstance["instance"]["networks"]:
623                     myInstance["instance"]["networks"][net_scenario] = {} 
624                 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
625                     myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
626                 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-use"] = net_datacenter
627     if args.netmap_create:
628         if "networks" not in myInstance["instance"]:
629             myInstance["instance"]["networks"] = {}
630         for net in args.netmap_create:
631             net_comma_list = net.split(",")
632             for net_comma in net_comma_list:
633                 net_tuple = net_comma.split("=")
634                 if len(net_tuple) == 1:
635                     net_scenario   = net_tuple[0].strip()
636                     net_datacenter = None
637                 elif len(net_tuple) == 2:
638                     net_scenario   = net_tuple[0].strip()
639                     net_datacenter = net_tuple[1].strip()
640                 else:
641                     print "error at netmap-create. Expected net-scenario=net-datacenter or net-scenario. (%s)?" % net_comma
642                     return
643                 if net_scenario not in myInstance["instance"]["networks"]:
644                     myInstance["instance"]["networks"][net_scenario] = {} 
645                 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
646                     myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
647                 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-create"] = net_datacenter
648     if args.keypair:
649         if "cloud-config" not in myInstance["instance"]:
650             myInstance["instance"]["cloud-config"] = {}
651         cloud_config = myInstance["instance"]["cloud-config"]
652         for key in args.keypair:
653             index = key.find(":")
654             if index<0:
655                 if "key-pairs" not in cloud_config:
656                     cloud_config["key-pairs"] = []
657                 cloud_config["key-pairs"].append(key)
658             else:
659                 user = key[:index]
660                 key_ = key[index+1:]
661                 key_list = key_.split(",")
662                 if "users" not in cloud_config:
663                     cloud_config["users"] = []
664                 cloud_config["users"].append({"name": user, "key-pairs": key_list  })
665     if args.keypair_auto:
666         try:
667             keys=[]
668             home = os.getenv("HOME")
669             user = os.getenv("USER")
670             files = os.listdir(home+'/.ssh')
671             for file in files:
672                 if file[-4:] == ".pub":
673                     with open(home+'/.ssh/'+file, 'r') as f:
674                         keys.append(f.read())
675             if not keys:
676                 print "Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh')
677                 return 1
678         except Exception as e:
679             print "Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e))
680             return 1
681         
682         if "cloud-config" not in myInstance["instance"]:
683             myInstance["instance"]["cloud-config"] = {}
684         cloud_config = myInstance["instance"]["cloud-config"]
685         if "key-pairs" not in cloud_config:
686             cloud_config["key-pairs"] = []
687         if user:
688             if "users" not in cloud_config:
689                 cloud_config["users"] = []
690             cloud_config["users"].append({"name": user, "key-pairs": keys })                    
691                         
692     payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
693     logger.debug("openmano request: %s", payload_req)
694     URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
695     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
696     logger.debug("openmano response: %s", mano_response.text )
697     if args.verbose==None:
698         args.verbose=0
699     
700     result = 0 if mano_response.status_code==200 else mano_response.status_code
701     content = mano_response.json()
702     #print json.dumps(content, indent=4)
703     if args.verbose >= 3:
704         print yaml.safe_dump(content, indent=4, default_flow_style=False)
705         return result
706
707     if mano_response.status_code == 200:
708         myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
709         if args.verbose >=1:
710             myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
711         if args.verbose >=2:
712             myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
713         print myoutput
714     else:
715         print content['error']['description']
716     return result
717
718 def instance_scenario_list(args):
719     #print "instance-scenario-list",args
720     if args.all:
721         tenant = "any"
722     else:
723         tenant = _get_tenant()
724     if args.name:
725         toshow = _get_item_uuid("instances", args.name, tenant)
726         URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, toshow)
727     else:
728         URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
729     mano_response = requests.get(URLrequest)
730     logger.debug("openmano response: %s", mano_response.text )
731     content = mano_response.json()
732     #print json.dumps(content, indent=4)
733     if args.verbose==None:
734         args.verbose=0
735
736     result = 0 if mano_response.status_code==200 else mano_response.status_code
737     if mano_response.status_code == 200:
738         if not args.name:
739             if args.verbose >= 3:
740                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
741                 return result
742             if len(content['instances']) == 0:
743                 print "No scenario instances were found."
744                 return result
745             for instance in content['instances']:
746                 myoutput = "%s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20))
747                 if args.verbose >=1:
748                     myoutput = "%s %s" %(myoutput, instance['created_at'].ljust(20))
749                 print myoutput
750                 if args.verbose >=2:
751                     print "Description: %s" %instance['description']
752         else:
753             if args.verbose:
754                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
755                 return result
756             instance = content
757             print "%s %s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20),instance['created_at'].ljust(20))
758             print "Description: %s" %instance['description']
759             print "Template scenario id: %s" %instance['scenario_id']
760             print "Template scenario name: %s" %instance['scenario_name']
761             print "---------------------------------------"
762             print "VNF instances: %d" %len(instance['vnfs'])
763             for vnf in instance['vnfs']:
764                 #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))
765                 print "    %s %s Template vnf id: %s" %(vnf['uuid'].ljust(38), vnf['vnf_name'].ljust(20), vnf['vnf_id'].ljust(38))
766             if len(instance['nets'])>0:
767                 print "---------------------------------------"
768                 print "Internal nets:"
769                 for net in instance['nets']:
770                     if net['created']:
771                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
772                 print "---------------------------------------"
773                 print "External nets:"
774                 for net in instance['nets']:
775                     if not net['created']:
776                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
777             print "---------------------------------------"
778             print "VM instances:"
779             for vnf in instance['vnfs']:
780                 for vm in vnf['vms']:
781                     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'])
782     else:
783         print content['error']['description']
784         if args.verbose:
785             print yaml.safe_dump(content, indent=4, default_flow_style=False)
786     return result
787
788 def instance_scenario_status(args):
789     print "instance-scenario-status"
790     return 0
791
792 def instance_scenario_delete(args):
793     if args.all:
794         tenant = "any"
795     else:
796         tenant = _get_tenant()
797     todelete = _get_item_uuid("instances", args.name, tenant=tenant)
798     #print "instance-scenario-delete",args
799     if not args.force:
800         r = raw_input("Delete scenario instance %s (y/N)? " %(args.name))
801         if  not (len(r)>0  and r[0].lower()=="y"):
802             return
803     URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, todelete)
804     mano_response = requests.delete(URLrequest)
805     logger.debug("openmano response: %s", mano_response.text )
806     result = 0 if mano_response.status_code==200 else mano_response.status_code
807     content = mano_response.json()
808     #print json.dumps(content, indent=4)
809     if mano_response.status_code == 200:
810         print content['result']
811     else:
812         print content['error']['description']
813     return result
814
815 def instance_scenario_action(args):
816     #print "instance-scenario-action", args
817     tenant = _get_tenant()
818     toact = _get_item_uuid("instances", args.name, tenant=tenant)
819     action={}
820     action[ args.action ] = args.param
821     if args.vnf:
822         action["vnfs"] = args.vnf
823     if args.vm:
824         action["vms"] = args.vm
825     
826     headers_req = {'content-type': 'application/json'}
827     payload_req = json.dumps(action, indent=4)
828     URLrequest = "http://%s:%s/openmano/%s/instances/%s/action" %(mano_host, mano_port, tenant, toact)
829     logger.debug("openmano request: %s", payload_req)
830     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
831     logger.debug("openmano response: %s", mano_response.text )
832     result = 0 if mano_response.status_code==200 else mano_response.status_code
833     content = mano_response.json()
834     #print json.dumps(content, indent=4)
835     if mano_response.status_code == 200:
836         if args.verbose:
837             print yaml.safe_dump(content, indent=4, default_flow_style=False)
838             return result
839         for uuid,c in content.iteritems():
840             print "%s %s %s" %(uuid.ljust(38), c['name'].ljust(20),c['description'].ljust(20))
841     else:
842         print content['error']['description']
843     return result
844
845
846 def instance_vnf_list(args):
847     print "instance-vnf-list"
848     return 0
849
850 def instance_vnf_status(args):
851     print "instance-vnf-status"
852     return 0
853
854 def tenant_create(args):
855     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
856     tenant_dict={"name": args.name}
857     if args.description!=None:
858         tenant_dict["description"] = args.description 
859     payload_req = json.dumps( {"tenant": tenant_dict })
860     
861     #print payload_req
862         
863     URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
864     logger.debug("openmano request: %s", payload_req)
865     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
866     logger.debug("openmano response: %s", mano_response.text )
867     return _print_verbose(mano_response, args.verbose)
868
869 def tenant_list(args):
870     #print "tenant-list",args
871     if args.name:
872         toshow = _get_item_uuid("tenants", args.name)
873         URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, toshow)
874     else:
875         URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
876     mano_response = requests.get(URLrequest)
877     logger.debug("openmano response: %s", mano_response.text )
878     if args.verbose==None:
879         args.verbose=0
880     if args.name!=None:
881         args.verbose += 1
882     return _print_verbose(mano_response, args.verbose)
883
884 def tenant_delete(args):
885     #print "tenant-delete",args
886     todelete = _get_item_uuid("tenants", args.name)
887     if not args.force:
888         r = raw_input("Delete tenant %s (y/N)? " %(args.name))
889         if  not (len(r)>0  and r[0].lower()=="y"):
890             return 0
891     URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, todelete)
892     mano_response = requests.delete(URLrequest)
893     logger.debug("openmano response: %s", mano_response.text )
894     result = 0 if mano_response.status_code==200 else mano_response.status_code
895     content = mano_response.json()
896     #print json.dumps(content, indent=4)
897     if mano_response.status_code == 200:
898         print content['result']
899     else:
900         print content['error']['description']
901     return result
902
903 def datacenter_attach(args):
904     tenant = _get_tenant()
905     datacenter = _get_datacenter(args.name)
906     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
907     
908     datacenter_dict={}
909     if args.vim_tenant_id != None:
910         datacenter_dict['vim_tenant'] = args.vim_tenant_id
911     if args.vim_tenant_name != None:
912         datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
913     if args.user != None:
914         datacenter_dict['vim_username'] = args.user
915     if args.password != None:
916         datacenter_dict['vim_password'] = args.password
917     if args.config!=None:
918         datacenter_dict["config"] = _load_file_or_yaml(args.config)
919     payload_req = json.dumps( {"datacenter": datacenter_dict })
920     
921     #print payload_req
922         
923     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
924     logger.debug("openmano request: %s", payload_req)
925     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
926     logger.debug("openmano response: %s", mano_response.text )
927     result = _print_verbose(mano_response, args.verbose)
928     #provide addional information if error
929     if mano_response.status_code != 200:
930         content = mano_response.json()
931         if "already in use for  'name'" in content['error']['description'] and \
932                 "to database vim_tenants table" in content['error']['description']:
933             print "Try to specify a different name with --vim-tenant-name"
934     return result
935
936
937 def datacenter_edit_vim_tenant(args):
938     tenant = _get_tenant()
939     datacenter = _get_datacenter(args.name)
940     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
941
942     if not (args.vim_tenant_id or args.vim_tenant_name or args.user or args.password or args.config):
943         raise OpenmanoCLIError("Error. At least one parameter must be updated.")
944
945     datacenter_dict = {}
946     if args.vim_tenant_id != None:
947         datacenter_dict['vim_tenant'] = args.vim_tenant_id
948     if args.vim_tenant_name != None:
949         datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
950     if args.user != None:
951         datacenter_dict['vim_username'] = args.user
952     if args.password != None:
953         datacenter_dict['vim_password'] = args.password
954     if args.config != None:
955         datacenter_dict["config"] = _load_file_or_yaml(args.config)
956     payload_req = json.dumps({"datacenter": datacenter_dict})
957
958     # print payload_req
959
960     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" % (mano_host, mano_port, tenant, datacenter)
961     logger.debug("openmano request: %s", payload_req)
962     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
963     logger.debug("openmano response: %s", mano_response.text)
964     result = _print_verbose(mano_response, args.verbose)
965
966     return result
967
968 def datacenter_detach(args):
969     if args.all:
970         tenant = "any"
971     else:
972         tenant = _get_tenant()
973     datacenter = _get_datacenter(args.name, tenant)
974     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
975     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
976     mano_response = requests.delete(URLrequest, headers=headers_req)
977     logger.debug("openmano response: %s", mano_response.text )
978     content = mano_response.json()
979     #print json.dumps(content, indent=4)
980     result = 0 if mano_response.status_code==200 else mano_response.status_code
981     if mano_response.status_code == 200:
982         print content['result']
983     else:
984         print content['error']['description']
985     return result
986
987 def datacenter_create(args):
988     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
989     datacenter_dict={"name": args.name, "vim_url": args.url}
990     if args.description!=None:
991         datacenter_dict["description"] = args.description 
992     if args.type!=None:
993         datacenter_dict["type"] = args.type 
994     if args.url!=None:
995         datacenter_dict["vim_url_admin"] = args.url_admin 
996     if args.config!=None:
997         datacenter_dict["config"] = _load_file_or_yaml(args.config)
998     if args.sdn_controller!=None:
999         tenant = _get_tenant()
1000         sdn_controller = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
1001         if not 'config' in datacenter_dict:
1002             datacenter_dict['config'] = {}
1003         datacenter_dict['config']['sdn-controller'] = sdn_controller
1004     payload_req = json.dumps( {"datacenter": datacenter_dict })
1005     
1006     #print payload_req
1007         
1008     URLrequest = "http://%s:%s/openmano/datacenters" %(mano_host, mano_port)
1009     logger.debug("openmano request: %s", payload_req)
1010     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1011     logger.debug("openmano response: %s", mano_response.text )
1012     return _print_verbose(mano_response, args.verbose)
1013
1014 def datacenter_delete(args):
1015     #print "datacenter-delete",args
1016     todelete = _get_item_uuid("datacenters", args.name, "any")
1017     if not args.force:
1018         r = raw_input("Delete datacenter %s (y/N)? " %(args.name))
1019         if  not (len(r)>0  and r[0].lower()=="y"):
1020             return 0
1021     URLrequest = "http://%s:%s/openmano/datacenters/%s" %(mano_host, mano_port, todelete)
1022     mano_response = requests.delete(URLrequest)
1023     logger.debug("openmano response: %s", mano_response.text )
1024     result = 0 if mano_response.status_code==200 else mano_response.status_code
1025     content = mano_response.json()
1026     #print json.dumps(content, indent=4)
1027     if mano_response.status_code == 200:
1028         print content['result']
1029     else:
1030         print content['error']['description']
1031     return result
1032
1033 def datacenter_list(args):
1034     #print "datacenter-list",args
1035     tenant='any' if args.all else _get_tenant()
1036     
1037     if args.name:
1038         toshow = _get_item_uuid("datacenters", args.name, tenant) 
1039         URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, toshow)
1040     else:
1041         URLrequest = "http://%s:%s/openmano/%s/datacenters" %(mano_host, mano_port, tenant)
1042     mano_response = requests.get(URLrequest)
1043     logger.debug("openmano response: %s", mano_response.text )
1044     if args.verbose==None:
1045         args.verbose=0
1046     if args.name!=None:
1047         args.verbose += 1
1048     return _print_verbose(mano_response, args.verbose)
1049
1050 def datacenter_sdn_port_mapping_set(args):
1051     tenant = _get_tenant()
1052     datacenter = _get_datacenter(args.name, tenant)
1053     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1054
1055     if not args.file:
1056         raise OpenmanoCLIError(
1057             "No yaml/json has been provided specifying the SDN port mapping")
1058
1059     port_mapping = yaml.load(datacenter_sdn_port_mapping_list(args))
1060     if len(port_mapping["sdn_port_mapping"]["ports_mapping"]) > 0:
1061         if not args.force:
1062             r = raw_input("Datacenter %s already contains a port mapping. Overwrite? (y/N)? " % (datacenter))
1063             if not (len(r) > 0 and r[0].lower() == "y"):
1064                 return 0
1065         args.force = True
1066         print datacenter_sdn_port_mapping_clear(args)
1067
1068     sdn_port_mapping = _load_file_or_yaml(args.file)
1069     payload_req = json.dumps({"sdn_port_mapping": sdn_port_mapping})
1070
1071     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1072     logger.debug("openmano request: %s", payload_req)
1073     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1074     logger.debug("openmano response: %s", mano_response.text)
1075
1076     if mano_response.status_code == 200:
1077         return yaml.safe_dump(mano_response.json())
1078     else:
1079         return mano_response.content
1080
1081 def datacenter_sdn_port_mapping_list(args):
1082     tenant = _get_tenant()
1083     datacenter = _get_datacenter(args.name, tenant)
1084
1085     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1086     mano_response = requests.get(URLrequest)
1087     logger.debug("openmano response: %s", mano_response.text)
1088
1089     if mano_response.status_code != 200:
1090         return mano_response.content
1091
1092     return yaml.safe_dump(mano_response.json())
1093
1094 def datacenter_sdn_port_mapping_clear(args):
1095     tenant = _get_tenant()
1096     datacenter = _get_datacenter(args.name, tenant)
1097
1098     if not args.force:
1099         r = raw_input("Clean SDN port mapping for datacenter %s (y/N)? " %(datacenter))
1100         if  not (len(r)>0  and r[0].lower()=="y"):
1101             return 0
1102
1103     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
1104     mano_response = requests.delete(URLrequest)
1105     logger.debug("openmano response: %s", mano_response.text)
1106
1107     if mano_response.status_code != 200:
1108         if "No port mapping for datacenter" in mano_response.content:
1109             return "No port mapping for datacenter " + datacenter + " has been found"
1110         return mano_response.content
1111
1112     return yaml.safe_dump(mano_response.json())
1113
1114 def sdn_controller_create(args):
1115     tenant = _get_tenant()
1116     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1117
1118     if not (args.ip and args.port and args.dpid and args.type):
1119         raise OpenmanoCLIError("The following arguments are required: ip, port, dpid, type")
1120
1121     controller_dict = {}
1122     controller_dict['name'] = args.name
1123     controller_dict['ip'] = args.ip
1124     controller_dict['port'] = int(args.port)
1125     controller_dict['dpid'] = args.dpid
1126     controller_dict['type'] = args.type
1127     if args.description != None:
1128         controller_dict['description'] = args.description
1129     if args.user != None:
1130         controller_dict['user'] = args.user
1131     if args.password != None:
1132         controller_dict['password'] = args.password
1133
1134     payload_req = json.dumps({"sdn_controller": controller_dict})
1135
1136     # print payload_req
1137
1138     URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" % (mano_host, mano_port, tenant)
1139     logger.debug("openmano request: %s", payload_req)
1140     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1141     logger.debug("openmano response: %s", mano_response.text)
1142     result = _print_verbose(mano_response, args.verbose)
1143
1144     return result
1145
1146 def sdn_controller_edit(args):
1147     tenant = _get_tenant()
1148     controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
1149     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1150
1151     if not (args.new_name or args.ip or args.port or args.dpid or args.type):
1152         raise OpenmanoCLIError("At least one parameter must be editd")
1153
1154     if not args.force:
1155         r = raw_input("Update SDN controller %s (y/N)? " %(args.name))
1156         if  not (len(r)>0  and r[0].lower()=="y"):
1157             return 0
1158
1159     controller_dict = {}
1160     if args.new_name != None:
1161         controller_dict['name'] = args.new_name
1162     if args.ip != None:
1163         controller_dict['ip'] = args.ip
1164     if args.port != None:
1165         controller_dict['port'] = int(args.port)
1166     if args.dpid != None:
1167         controller_dict['dpid'] = args.dpid
1168     if args.type != None:
1169         controller_dict['type'] = args.type
1170     if args.description != None:
1171         controller_dict['description'] = args.description
1172     if args.user != None:
1173         controller_dict['user'] = args.user
1174     if args.password != None:
1175         controller_dict['password'] = args.password
1176
1177     payload_req = json.dumps({"sdn_controller": controller_dict})
1178
1179     # print payload_req
1180
1181     URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
1182     logger.debug("openmano request: %s", payload_req)
1183     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1184     logger.debug("openmano response: %s", mano_response.text)
1185     result = _print_verbose(mano_response, args.verbose)
1186
1187     return result
1188
1189 def sdn_controller_list(args):
1190     tenant = _get_tenant()
1191     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1192
1193     if args.name:
1194         toshow = _get_item_uuid("sdn_controllers", args.name, tenant)
1195         URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" %(mano_host, mano_port, tenant, toshow)
1196     else:
1197         URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" %(mano_host, mano_port, tenant)
1198     #print URLrequest
1199     mano_response = requests.get(URLrequest)
1200     logger.debug("openmano response: %s", mano_response.text )
1201     if args.verbose==None:
1202         args.verbose=0
1203     if args.name!=None:
1204         args.verbose += 1
1205
1206     result = json.dumps(mano_response.json(), indent=4)
1207     return result
1208
1209 def sdn_controller_delete(args):
1210     tenant = _get_tenant()
1211     controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
1212
1213     if not args.force:
1214         r = raw_input("Delete SDN controller %s (y/N)? " % (args.name))
1215         if not (len(r) > 0 and r[0].lower() == "y"):
1216             return 0
1217
1218     URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
1219     mano_response = requests.delete(URLrequest)
1220     logger.debug("openmano response: %s", mano_response.text)
1221     result = _print_verbose(mano_response, args.verbose)
1222
1223     return result
1224
1225 def vim_action(args):
1226     #print "datacenter-net-action",args
1227     tenant = _get_tenant()
1228     datacenter = _get_datacenter(args.datacenter, tenant)
1229     if args.verbose==None:
1230         args.verbose=0
1231     if args.action=="list":
1232         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
1233         if args.name!=None:
1234             args.verbose += 1
1235             URLrequest += "/" + args.name
1236         mano_response = requests.get(URLrequest)
1237         logger.debug("openmano response: %s", mano_response.text )
1238         return _print_verbose(mano_response, args.verbose)
1239     elif args.action=="delete":
1240         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss/%s" %(mano_host, mano_port, tenant, datacenter, args.item, args.name)
1241         mano_response = requests.delete(URLrequest)
1242         logger.debug("openmano response: %s", mano_response.text )
1243         result = 0 if mano_response.status_code==200 else mano_response.status_code
1244         content = mano_response.json()
1245         #print json.dumps(content, indent=4)
1246         if mano_response.status_code == 200:
1247             print content['result']
1248         else:
1249             print content['error']['description']
1250         return result
1251     elif args.action=="create":
1252         headers_req = {'content-type': 'application/yaml'}
1253         if args.file:
1254             create_dict = _load_file_or_yaml(args.file)
1255             if args.item not in create_dict:
1256                 create_dict = {args.item: create_dict}
1257         else:
1258             create_dict = {args.item:{}}
1259         if args.name:
1260             create_dict[args.item]['name'] = args.name
1261         #if args.description:
1262         #    create_dict[args.item]['description'] = args.description
1263         if args.item=="network":
1264             if args.bind_net:
1265                 create_dict[args.item]['bind_net'] = args.bind_net
1266             if args.type:
1267                 create_dict[args.item]['type'] = args.type
1268             if args.shared:
1269                 create_dict[args.item]['shared'] = args.shared
1270         if "name" not in create_dict[args.item]:
1271             print "You must provide a name in the descriptor file or with the --name option"
1272             return
1273         payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
1274         logger.debug("openmano request: %s", payload_req)
1275         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
1276         mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
1277         logger.debug("openmano response: %s", mano_response.text )
1278         if args.verbose==None:
1279             args.verbose=0
1280         return _print_verbose(mano_response, args.verbose)
1281
1282
1283 def datacenter_net_action(args):
1284     if args.action == "net-update":
1285         print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-import' instead!!!"
1286         print
1287         args.action = "netmap-delete"
1288         args.netmap = None
1289         args.all = True
1290         r = datacenter_netmap_action(args)
1291         if r == 0:
1292             args.force = True
1293             args.action = "netmap-import"
1294             r = datacenter_netmap_action(args)
1295         return r
1296
1297     if args.action == "net-edit":
1298         args.netmap = args.net
1299         args.name = None
1300     elif args.action == "net-list":
1301         args.netmap = None
1302     elif args.action == "net-delete":
1303         args.netmap = args.net
1304         args.all = False
1305           
1306     args.action = "netmap" + args.action[3:]
1307     args.vim_name=None
1308     args.vim_id=None
1309     print "This command is deprecated, use 'openmano datacenter-%s' instead!!!" % args.action
1310     print
1311     return datacenter_netmap_action(args)
1312
1313 def datacenter_netmap_action(args):
1314     tenant = _get_tenant()
1315     datacenter = _get_datacenter(args.datacenter, tenant)
1316     #print "datacenter_netmap_action",args
1317     payload_req = None
1318     if args.verbose==None:
1319         args.verbose=0
1320     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1321     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/netmaps" %(mano_host, mano_port, tenant, datacenter)
1322         
1323     if args.action=="netmap-list":
1324         if args.netmap:
1325             URLrequest += "/" + args.netmap
1326             args.verbose += 1
1327         mano_response = requests.get(URLrequest)
1328             
1329     elif args.action=="netmap-delete":
1330         if args.netmap and args.all:
1331             print "you can not use a netmap name and the option --all at the same time"
1332             return 1
1333         if args.netmap:
1334             force_text= "Delete default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter)
1335             URLrequest += "/" + args.netmap
1336         elif args.all: 
1337             force_text="Delete all default netmaps from datacenter '%s' (y/N)? " % (datacenter)
1338         else:
1339             print "you must specify a netmap name or the option --all"
1340             return 1
1341         if not args.force:
1342             r = raw_input(force_text)
1343             if  len(r)>0  and r[0].lower()=="y":
1344                 pass
1345             else:
1346                 return 0
1347         mano_response = requests.delete(URLrequest, headers=headers_req)
1348     elif args.action=="netmap-import":
1349         if not args.force:
1350             r = raw_input("Create all the available networks from datacenter '%s' as default netmaps (y/N)? " % (datacenter))
1351             if  len(r)>0  and r[0].lower()=="y":
1352                 pass
1353             else:
1354                 return 0
1355         URLrequest += "/upload"
1356         mano_response = requests.post(URLrequest, headers=headers_req)
1357     elif args.action=="netmap-edit" or args.action=="netmap-create":
1358         if args.file:
1359             payload = _load_file_or_yaml(args.file)
1360         else:
1361             payload = {}
1362         if "netmap" not in payload:
1363             payload = {"netmap": payload}
1364         if args.name:
1365             payload["netmap"]["name"] = args.name
1366         if args.vim_id:
1367             payload["netmap"]["vim_id"] = args.vim_id
1368         if args.action=="netmap-create" and args.vim_name:
1369             payload["netmap"]["vim_name"] = args.vim_name
1370         payload_req = json.dumps(payload)
1371         logger.debug("openmano request: %s", payload_req)
1372         
1373         if args.action=="netmap-edit" and not args.force:
1374             if len(payload["netmap"]) == 0:
1375                 print "You must supply some parameter to edit"
1376                 return 1
1377             r = raw_input("Edit default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter))
1378             if  len(r)>0  and r[0].lower()=="y":
1379                 pass
1380             else:
1381                 return 0
1382             URLrequest += "/" + args.netmap
1383             mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1384         else: #netmap-create
1385             if "vim_name" not in payload["netmap"] and "vim_id" not in payload["netmap"]:
1386                 print "You must supply either --vim-id or --vim-name option; or include one of them in the file descriptor"
1387                 return 1
1388             mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1389
1390     logger.debug("openmano response: %s", mano_response.text )
1391     return _print_verbose(mano_response, args.verbose)
1392
1393 def element_edit(args):
1394     element = _get_item_uuid(args.element, args.name)
1395     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1396     URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, args.element, element)
1397     payload=_load_file_or_yaml(args.file)
1398     if args.element[:-1] not in payload:
1399         payload = {args.element[:-1]: payload }
1400     payload_req = json.dumps(payload)
1401     
1402     #print payload_req
1403     if not args.force or (args.name==None and args.filer==None):
1404         r = raw_input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
1405         if  len(r)>0  and r[0].lower()=="y":
1406             pass
1407         else:
1408             return 0
1409     logger.debug("openmano request: %s", payload_req)
1410     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1411     logger.debug("openmano response: %s", mano_response.text )
1412     if args.verbose==None:
1413         args.verbose=0
1414     if args.name!=None:
1415         args.verbose += 1
1416     return _print_verbose(mano_response, args.verbose)
1417
1418
1419 def datacenter_edit(args):
1420     tenant = _get_tenant()
1421     element = _get_item_uuid('datacenters', args.name, tenant)
1422     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1423     URLrequest = "http://%s:%s/openmano/datacenters/%s" % (mano_host, mano_port, element)
1424
1425     has_arguments = False
1426     if args.file != None:
1427         has_arguments = True
1428         payload = _load_file_or_yaml(args.file)
1429     else:
1430         payload = {}
1431
1432     if args.sdn_controller != None:
1433         has_arguments = True
1434         if not 'config' in payload:
1435             payload['config'] = {}
1436         if not 'sdn-controller' in payload['config']:
1437             payload['config']['sdn-controller'] = {}
1438         if args.sdn_controller == 'null':
1439             payload['config']['sdn-controller'] = None
1440         else:
1441             payload['config']['sdn-controller'] = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
1442
1443     if not has_arguments:
1444         raise OpenmanoCLIError("At least one argument must be provided to modify the datacenter")
1445
1446     if 'datacenter' not in payload:
1447         payload = {'datacenter': payload}
1448     payload_req = json.dumps(payload)
1449
1450     # print payload_req
1451     if not args.force or (args.name == None and args.filer == None):
1452         r = raw_input(" Edit datacenter " + args.name + " (y/N)? ")
1453         if len(r) > 0 and r[0].lower() == "y":
1454             pass
1455         else:
1456             return 0
1457     logger.debug("openmano request: %s", payload_req)
1458     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1459     logger.debug("openmano response: %s", mano_response.text)
1460     if args.verbose == None:
1461         args.verbose = 0
1462     if args.name != None:
1463         args.verbose += 1
1464     return _print_verbose(mano_response, args.verbose)
1465
1466 def version(args):
1467     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1468     URLrequest = "http://%s:%s/openmano/version" % (mano_host, mano_port)
1469
1470     mano_response = requests.get(URLrequest, headers=headers_req)
1471     logger.debug("openmano response: %s", mano_response.text)
1472     print mano_response.text
1473
1474
1475 global mano_host
1476 global mano_port
1477 global mano_tenant
1478
1479 if __name__=="__main__":
1480     
1481     mano_tenant = os.getenv('OPENMANO_TENANT', None)
1482     mano_host = os.getenv('OPENMANO_HOST',"localhost")
1483     mano_port = os.getenv('OPENMANO_PORT',"9090")
1484     mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
1485     
1486     main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
1487     main_parser.add_argument('--version', action='version', help="get version of this client",
1488                             version='%(prog)s client version ' + __version__ +
1489                                     " (Note: use '%(prog)s version' to get server version)")
1490
1491     subparsers = main_parser.add_subparsers(help='commands')
1492     
1493     parent_parser = argparse.ArgumentParser(add_help=False)
1494     parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
1495     parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1496
1497     config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
1498     config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
1499     config_parser.set_defaults(func=config)
1500
1501     version_parser = subparsers.add_parser('version', parents=[parent_parser], help="get server version")
1502     version_parser.set_defaults(func=version)
1503
1504     vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
1505     vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
1506     vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1507     vnf_create_parser.add_argument("--description", action="store", help="description of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1508     vnf_create_parser.add_argument("--image-path", action="store",  help="change image path locations (overwritten)")
1509     vnf_create_parser.add_argument("--image-name", action="store",  help="change image name (overwritten)")
1510     vnf_create_parser.add_argument("--image-checksum", action="store",  help="change image checksum (overwritten)")
1511     vnf_create_parser.set_defaults(func=vnf_create)
1512
1513     vnf_list_parser = subparsers.add_parser('vnf-list', parents=[parent_parser], help="lists information about a vnf")
1514     vnf_list_parser.add_argument("name", nargs='?', help="name of the VNF")
1515     vnf_list_parser.add_argument("-a", "--all", action="store_true", help="shows all vnfs, not only the owned or public ones")
1516     #vnf_list_parser.add_argument('--descriptor', help="prints the VNF descriptor", action="store_true")
1517     vnf_list_parser.set_defaults(func=vnf_list)
1518     
1519     vnf_delete_parser = subparsers.add_parser('vnf-delete', parents=[parent_parser], help="deletes a vnf from the catalogue")
1520     vnf_delete_parser.add_argument("name", action="store", help="name or uuid of the VNF to be deleted")
1521     vnf_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1522     vnf_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1523     vnf_delete_parser.set_defaults(func=vnf_delete)
1524     
1525     scenario_create_parser = subparsers.add_parser('scenario-create', parents=[parent_parser], help="adds a scenario into the OPENMANO DB")
1526     scenario_create_parser.add_argument("file", action="store", help="location of the YAML file describing the scenario").completer = FilesCompleter
1527     scenario_create_parser.add_argument("--name", action="store", help="name of the scenario (if it exists in the YAML scenario, it is overwritten)")
1528     scenario_create_parser.add_argument("--description", action="store", help="description of the scenario (if it exists in the YAML scenario, it is overwritten)")
1529     scenario_create_parser.set_defaults(func=scenario_create)
1530
1531     scenario_list_parser = subparsers.add_parser('scenario-list', parents=[parent_parser], help="lists information about a scenario")
1532     scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario")
1533     #scenario_list_parser.add_argument('--descriptor', help="prints the scenario descriptor", action="store_true")
1534     scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all scenarios, not only the owned or public ones")
1535     scenario_list_parser.set_defaults(func=scenario_list)
1536     
1537     scenario_delete_parser = subparsers.add_parser('scenario-delete', parents=[parent_parser], help="deletes a scenario from the OPENMANO DB")
1538     scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario to be deleted")
1539     scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1540     scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1541     scenario_delete_parser.set_defaults(func=scenario_delete)
1542
1543     scenario_deploy_parser = subparsers.add_parser('scenario-deploy', parents=[parent_parser], help="deploys a scenario")
1544     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be deployed")
1545     scenario_deploy_parser.add_argument("name", action="store", help="name of the instance")
1546     scenario_deploy_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1547     scenario_deploy_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1548     scenario_deploy_parser.add_argument("--description", action="store", help="description of the instance")
1549     scenario_deploy_parser.set_defaults(func=scenario_deploy)
1550     
1551     scenario_deploy_parser = subparsers.add_parser('scenario-verify', help="verifies if a scenario can be deployed (deploys it and deletes it)")
1552     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be verified")
1553     scenario_deploy_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1554     scenario_deploy_parser.set_defaults(func=scenario_verify)
1555     
1556     instance_scenario_create_parser = subparsers.add_parser('instance-scenario-create', parents=[parent_parser], help="deploys a scenario")
1557     instance_scenario_create_parser.add_argument("file", nargs='?', help="descriptor of the instance. Must be a file or yaml/json text")
1558     instance_scenario_create_parser.add_argument("--scenario", action="store", help="name or uuid of the scenario to be deployed")
1559     instance_scenario_create_parser.add_argument("--name", action="store", help="name of the instance")
1560     instance_scenario_create_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1561     instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1562     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")
1563     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")
1564     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")
1565     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")
1566     instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
1567     instance_scenario_create_parser.set_defaults(func=instance_create)
1568
1569     instance_scenario_list_parser = subparsers.add_parser('instance-scenario-list', parents=[parent_parser], help="lists information about a scenario instance")
1570     instance_scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario instance")
1571     instance_scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all instance-scenarios, not only the owned")
1572     instance_scenario_list_parser.set_defaults(func=instance_scenario_list)
1573
1574     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)")
1575     instance_scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario instance to be deleted")
1576     instance_scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1577     instance_scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1578     instance_scenario_delete_parser.set_defaults(func=instance_scenario_delete)
1579     
1580     instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
1581     instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1582     instance_scenario_action_parser.add_argument("action", action="store", type=str, \
1583             choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console"],\
1584             help="action to send")
1585     instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console type (novnc, ...), reboot type (TODO)")
1586     instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
1587     instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
1588     instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
1589
1590     #instance_scenario_status_parser = subparsers.add_parser('instance-scenario-status', help="show the status of a scenario instance")
1591     #instance_scenario_status_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1592     #instance_scenario_status_parser.set_defaults(func=instance_scenario_status)
1593     
1594     tenant_create_parser = subparsers.add_parser('tenant-create', parents=[parent_parser], help="creates a new tenant")
1595     tenant_create_parser.add_argument("name", action="store", help="name for the tenant")
1596     tenant_create_parser.add_argument("--description", action="store", help="description of the tenant")
1597     tenant_create_parser.set_defaults(func=tenant_create)
1598
1599     tenant_delete_parser = subparsers.add_parser('tenant-delete', parents=[parent_parser], help="deletes a tenant from the catalogue")
1600     tenant_delete_parser.add_argument("name", action="store", help="name or uuid of the tenant to be deleted")
1601     tenant_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1602     tenant_delete_parser.set_defaults(func=tenant_delete)
1603
1604     tenant_list_parser = subparsers.add_parser('tenant-list', parents=[parent_parser], help="lists information about a tenant")
1605     tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
1606     tenant_list_parser.set_defaults(func=tenant_list)
1607
1608     element_edit_parser = subparsers.add_parser('tenant-edit', parents=[parent_parser], help="edits one tenant")
1609     element_edit_parser.add_argument("name", help="name or uuid of the tenant")
1610     element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1611     element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1612     element_edit_parser.set_defaults(func=element_edit, element='tenants')
1613
1614     datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
1615     datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
1616     datacenter_create_parser.add_argument("url", action="store", help="url for the datacenter")
1617     datacenter_create_parser.add_argument("--url_admin", action="store", help="url for administration for the datacenter")
1618     datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
1619     datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1620     datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
1621     datacenter_create_parser.add_argument("--sdn-controller", action="store", help="Name or uuid of the SDN controller to be used", dest='sdn_controller')
1622     datacenter_create_parser.set_defaults(func=datacenter_create)
1623
1624     datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
1625     datacenter_delete_parser.add_argument("name", action="store", help="name or uuid of the datacenter to be deleted")
1626     datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1627     datacenter_delete_parser.set_defaults(func=datacenter_delete)
1628
1629     datacenter_edit_parser = subparsers.add_parser('datacenter-edit', parents=[parent_parser], help="Edit datacenter")
1630     datacenter_edit_parser.add_argument("name", help="name or uuid of the datacenter")
1631     datacenter_edit_parser.add_argument("--file", help="json/yaml text or file with the changes").completer = FilesCompleter
1632     datacenter_edit_parser.add_argument("--sdn-controller", action="store",
1633                                           help="Name or uuid of the SDN controller to be used. Specify 'null' to clear entry", dest='sdn_controller')
1634     datacenter_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
1635     datacenter_edit_parser.set_defaults(func=datacenter_edit)
1636
1637     datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
1638     datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
1639     datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
1640     datacenter_list_parser.set_defaults(func=datacenter_list)
1641
1642     datacenter_attach_parser = subparsers.add_parser('datacenter-attach', parents=[parent_parser], help="associates a datacenter to the operating tenant")
1643     datacenter_attach_parser.add_argument("name", help="name or uuid of the datacenter")
1644     datacenter_attach_parser.add_argument('--vim-tenant-id', action='store', help="specify a datacenter tenant to use. A new one is created by default")
1645     datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1646     datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1647     datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1648     datacenter_attach_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1649     datacenter_attach_parser.set_defaults(func=datacenter_attach)
1650
1651     datacenter_edit_vim_tenant_parser = subparsers.add_parser('datacenter-edit-vim-tenant', parents=[parent_parser],
1652                                                      help="Edit the association of a datacenter to the operating tenant")
1653     datacenter_edit_vim_tenant_parser.add_argument("name", help="name or uuid of the datacenter")
1654     datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-id', action='store',
1655                                           help="specify a datacenter tenant to use. A new one is created by default")
1656     datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1657     datacenter_edit_vim_tenant_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1658     datacenter_edit_vim_tenant_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1659     datacenter_edit_vim_tenant_parser.add_argument("--config", action="store",
1660                                           help="aditional configuration in json/yaml format")
1661     datacenter_edit_vim_tenant_parser.set_defaults(func=datacenter_edit_vim_tenant)
1662
1663     datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
1664     datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
1665     datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
1666     datacenter_detach_parser.set_defaults(func=datacenter_detach)
1667
1668     #=======================datacenter_sdn_port_mapping_xxx section=======================
1669     #datacenter_sdn_port_mapping_set
1670     datacenter_sdn_port_mapping_set_parser = subparsers.add_parser('datacenter-sdn-port-mapping-set',
1671                                                                    parents=[parent_parser],
1672                                                                    help="Load a file with the mapping of physical ports "
1673                                                                         "and the ports of the dataplaneswitch controlled "
1674                                                                         "by a datacenter")
1675     datacenter_sdn_port_mapping_set_parser.add_argument("name", action="store", help="specifies the datacenter")
1676     datacenter_sdn_port_mapping_set_parser.add_argument("file",
1677                                                         help="json/yaml text or file with the port mapping").completer = FilesCompleter
1678     datacenter_sdn_port_mapping_set_parser.add_argument("-f", "--force", action="store_true",
1679                                                           help="forces overwriting without asking")
1680     datacenter_sdn_port_mapping_set_parser.set_defaults(func=datacenter_sdn_port_mapping_set)
1681
1682     #datacenter_sdn_port_mapping_list
1683     datacenter_sdn_port_mapping_list_parser = subparsers.add_parser('datacenter-sdn-port-mapping-list',
1684                                                                     parents=[parent_parser],
1685                                                                     help="Show the SDN port mapping in a datacenter")
1686     datacenter_sdn_port_mapping_list_parser.add_argument("name", action="store", help="specifies the datacenter")
1687     datacenter_sdn_port_mapping_list_parser.set_defaults(func=datacenter_sdn_port_mapping_list)
1688
1689     # datacenter_sdn_port_mapping_clear
1690     datacenter_sdn_port_mapping_clear_parser = subparsers.add_parser('datacenter-sdn-port-mapping-clear',
1691                                                                     parents=[parent_parser],
1692                                                                     help="Clean the the SDN port mapping in a datacenter")
1693     datacenter_sdn_port_mapping_clear_parser.add_argument("name", action="store",
1694                                                          help="specifies the datacenter")
1695     datacenter_sdn_port_mapping_clear_parser.add_argument("-f", "--force", action="store_true",
1696                                               help="forces clearing without asking")
1697     datacenter_sdn_port_mapping_clear_parser.set_defaults(func=datacenter_sdn_port_mapping_clear)
1698     # =======================
1699
1700     # =======================sdn_controller_xxx section=======================
1701     # sdn_controller_create
1702     sdn_controller_create_parser = subparsers.add_parser('sdn-controller-create', parents=[parent_parser],
1703                                                         help="Creates an SDN controller entity within RO")
1704     sdn_controller_create_parser.add_argument("name", help="name of the SDN controller")
1705     sdn_controller_create_parser.add_argument("--description", action="store", help="description of the SDN controller")
1706     sdn_controller_create_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
1707     sdn_controller_create_parser.add_argument("--port", action="store", help="Port of the SDN controller")
1708     sdn_controller_create_parser.add_argument("--dpid", action="store",
1709                                              help="DPID of the dataplane switch controlled by this SDN controller")
1710     sdn_controller_create_parser.add_argument("--type", action="store",
1711                                              help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
1712     sdn_controller_create_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
1713     sdn_controller_create_parser.add_argument("--passwd", action="store", dest='password',
1714                                              help="password credentials for the SDN controller")
1715     sdn_controller_create_parser.set_defaults(func=sdn_controller_create)
1716
1717     # sdn_controller_edit
1718     sdn_controller_edit_parser = subparsers.add_parser('sdn-controller-edit', parents=[parent_parser],
1719                                                         help="Update one or more options of a SDN controller")
1720     sdn_controller_edit_parser.add_argument("name", help="name or uuid of the SDN controller", )
1721     sdn_controller_edit_parser.add_argument("--name", action="store", help="Update the name of the SDN controller",
1722                                               dest='new_name')
1723     sdn_controller_edit_parser.add_argument("--description", action="store", help="description of the SDN controller")
1724     sdn_controller_edit_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
1725     sdn_controller_edit_parser.add_argument("--port", action="store", help="Port of the SDN controller")
1726     sdn_controller_edit_parser.add_argument("--dpid", action="store",
1727                                              help="DPID of the dataplane switch controlled by this SDN controller")
1728     sdn_controller_edit_parser.add_argument("--type", action="store",
1729                                              help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
1730     sdn_controller_edit_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
1731     sdn_controller_edit_parser.add_argument("--password", action="store",
1732                                              help="password credentials for the SDN controller", dest='password')
1733     sdn_controller_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
1734     #TODO: include option --file
1735     sdn_controller_edit_parser.set_defaults(func=sdn_controller_edit)
1736
1737     #sdn_controller_list
1738     sdn_controller_list_parser = subparsers.add_parser('sdn-controller-list',
1739                                                                     parents=[parent_parser],
1740                                                                     help="List the SDN controllers")
1741     sdn_controller_list_parser.add_argument("name", nargs='?', help="name or uuid of the SDN controller")
1742     sdn_controller_list_parser.set_defaults(func=sdn_controller_list)
1743
1744     # sdn_controller_delete
1745     sdn_controller_delete_parser = subparsers.add_parser('sdn-controller-delete',
1746                                                                     parents=[parent_parser],
1747                                                                     help="Delete the the SDN controller")
1748     sdn_controller_delete_parser.add_argument("name", help="name or uuid of the SDN controller")
1749     sdn_controller_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1750     sdn_controller_delete_parser.set_defaults(func=sdn_controller_delete)
1751     # =======================
1752
1753     action_dict={'net-update': 'retrieves external networks from datacenter',
1754                  'net-edit': 'edits an external network',
1755                  'net-delete': 'deletes an external network',
1756                  'net-list': 'lists external networks from a datacenter'
1757                  }
1758     for item in action_dict:
1759         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1760         datacenter_action_parser.add_argument("datacenter", help="name or uuid of the datacenter")
1761         if item=='net-edit' or item=='net-delete':
1762             datacenter_action_parser.add_argument("net", help="name or uuid of the datacenter net")
1763         if item=='net-edit':
1764             datacenter_action_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1765         if item!='net-list':
1766             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1767         datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
1768
1769
1770     action_dict={'netmap-import': 'create network senario netmap base on the datacenter networks',
1771                  'netmap-create': 'create a new network senario netmap',
1772                  'netmap-edit':   'edit name of a network senario netmap',
1773                  'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
1774                  'netmap-list':   'list/show network scenario netmaps'
1775                  }
1776     for item in action_dict:
1777         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1778         datacenter_action_parser.add_argument("--datacenter", help="name or uuid of the datacenter")
1779         #if item=='net-add':
1780         #    datacenter_action_parser.add_argument("net", help="name of the network")
1781         if item=='netmap-delete':
1782             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to delete")
1783             datacenter_action_parser.add_argument("--all", action="store_true", help="delete all netmap of this datacenter")
1784             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1785         if item=='netmap-edit':
1786             datacenter_action_parser.add_argument("netmap", help="name or uuid of the datacenter netmap do edit")
1787             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file with the changes").completer = FilesCompleter
1788             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap")
1789             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1790             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1791         if item=='netmap-list':
1792             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to show")
1793         if item=='netmap-create':
1794             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file descriptor with the changes").completer = FilesCompleter
1795             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
1796             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1797             datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
1798         if item=='netmap-import':
1799             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1800         datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)
1801     
1802     for item in ("network", "tenant", "image"):
1803         if item=="network":
1804             commnad_name = 'vim-net'
1805         else:
1806             commnad_name = 'vim-'+item
1807         vim_item_list_parser = subparsers.add_parser(commnad_name + '-list', parents=[parent_parser], help="list the vim " + item + "s")
1808         vim_item_list_parser.add_argument("name", nargs='?', help="name or uuid of the " + item + "s")
1809         vim_item_list_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1810         vim_item_list_parser.set_defaults(func=vim_action, item=item, action="list")
1811
1812         vim_item_del_parser = subparsers.add_parser(commnad_name + '-delete', parents=[parent_parser], help="list the vim " + item + "s")
1813         vim_item_del_parser.add_argument("name", help="name or uuid of the " + item + "s")
1814         vim_item_del_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1815         vim_item_del_parser.set_defaults(func=vim_action, item=item, action="delete")
1816
1817         if item == "network" or item == "tenant":
1818             vim_item_create_parser = subparsers.add_parser(commnad_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
1819             vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the %s. Must be a file or yaml/json text" % item).completer = FilesCompleter
1820             vim_item_create_parser.add_argument("--name", action="store", help="name of the %s" % item  )
1821             vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1822             if item=="network":
1823                 vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
1824                 vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
1825                 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>'")
1826             else:
1827                 vim_item_create_parser.add_argument("--description", action="store", help="description of the %s" % item)
1828             vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
1829
1830     argcomplete.autocomplete(main_parser)
1831     
1832     try:
1833         args = main_parser.parse_args()
1834         #logging info
1835         level = logging.CRITICAL
1836         streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
1837         if "debug" in args and args.debug:
1838             level = logging.DEBUG
1839         logging.basicConfig(format=streamformat, level= level)
1840         logger = logging.getLogger('mano')
1841         logger.setLevel(level)
1842         result = args.func(args)
1843         if result == None:
1844             result = 0
1845         #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
1846     except (requests.exceptions.ConnectionError):
1847         print "Connection error: not possible to contact OPENMANO-SERVER (openmanod)"
1848         result = -2
1849     except (KeyboardInterrupt):
1850         print 'Exiting openmano'
1851         result = -3
1852     except (SystemExit, ArgumentParserError):
1853         result = -4
1854     except OpenmanoCLIError as e:
1855         print str(e)
1856         result = -5
1857     
1858     #print result
1859     exit(result)
1860