Added *.pyo to .gitignore-common; minor typo fixed in openmano client
[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"
30 __date__ ="$09-oct-2014 09:09:48$"
31 __version__="0.4.7-r511"
32 version_date="Oct 2016"
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         for content in content_list:
124             if "uuid" in content:
125                 uuid = content['uuid']
126             elif "id" in content:
127                 uuid = content['id']
128             elif "vim_id" in content:
129                 uuid = content['vim_id']
130             myoutput = "%s %s" %(uuid.ljust(38),content['name'].ljust(20))
131             if "status" in content:
132                 myoutput += " " + content['status'].ljust(20)
133             elif "enabled" in content and not content["enabled"]:
134                 myoutput += " enabled=False".ljust(20)
135             if verbose_level >=1:
136                 if 'created_at' in content:
137                     myoutput += " " + content['created_at'].ljust(20)
138                 if verbose_level >=2:
139                     new_line='\n'
140                     if 'type' in content and content['type']!=None:
141                         myoutput += new_line + "  Type: " + content['type'].ljust(29)
142                         new_line=''
143                     if 'description' in content and content['description']!=None:
144                         myoutput += new_line + "  Description: " + content['description'].ljust(20)
145             print myoutput
146     else:
147         print content['error']['description']
148     return result
149
150 def parser_json_yaml(file_name):
151     try:
152         f = file(file_name, "r")
153         text = f.read()
154         f.close()
155     except Exception as e:
156         return (False, str(e))
157            
158     #Read and parse file
159     if file_name[-5:]=='.yaml' or file_name[-4:]=='.yml' or (file_name[-5:]!='.json' and '\t' not in text):
160         try:
161             config = yaml.load(text)
162         except yaml.YAMLError as exc:
163             error_pos = ""
164             if hasattr(exc, 'problem_mark'):
165                 mark = exc.problem_mark
166                 error_pos = " at line:%s column:%s" % (mark.line+1, mark.column+1)
167             return (False, "Error loading file '"+file_name+"' yaml format error" + error_pos)
168     else: #json
169         try:
170             config = json.loads(text) 
171         except Exception as e:
172             return (False, "Error loading file '"+file_name+"' json format error " + str(e) )
173
174     return True, config
175
176 def _load_file_or_yaml(content):
177     '''
178     'content' can be or a yaml/json file or a text containing a yaml/json text format
179     This function autodetect, trying to load and parse the file,
180     if fails trying to parse the 'content' text
181     Returns the dictionary once parsed, or print an error and finish the program
182     '''
183     #Check config file exists
184     if os.path.isfile(content):
185         r,payload = parser_json_yaml(content)
186         if not r:
187             print payload
188             exit(-1)
189     elif "{" in content or ":" in content:
190         try:
191             payload = yaml.load(content)
192         except yaml.YAMLError as exc:
193             error_pos = ""
194             if hasattr(exc, 'problem_mark'):
195                 mark = exc.problem_mark
196                 error_pos = " at position: (%s:%s)" % (mark.line+1, mark.column+1)
197             print "Error loading yaml/json text"+error_pos
198             exit (-1)
199     else:
200         print "'%s' is neither a valid file nor a yaml/json content" % content
201         exit(-1)
202     return payload
203
204 def _get_item_uuid(item, item_name_id, tenant=None):
205     if tenant:
206         URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, tenant, item)
207     else:
208         URLrequest = "http://%s:%s/openmano/%s" %(mano_host, mano_port, item)
209     mano_response = requests.get(URLrequest)
210     logger.debug("openmano response: %s", mano_response.text )
211     content = mano_response.json()
212     #print content
213     found = 0
214     for i in content[item]:
215         if i["uuid"] == item_name_id:
216             return item_name_id
217         if i["name"] == item_name_id:
218             uuid = i["uuid"]
219             found += 1
220     if found == 0:
221         raise OpenmanoCLIError("No %s found with name/uuid '%s'" %(item[:-1], item_name_id))
222     elif found > 1:
223         raise OpenmanoCLIError("%d %s found with name '%s'. uuid must be used" %(found, item, item_name_id))
224     return uuid
225
226 # def check_valid_uuid(uuid):
227 #     id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
228 #     try:
229 #         js_v(uuid, id_schema)
230 #         return True
231 #     except js_e.ValidationError:
232 #         return False
233     
234 def _get_tenant(tenant_name_id = None):
235     if not tenant_name_id:
236         tenant_name_id = mano_tenant
237         if not mano_tenant:
238             raise OpenmanoCLIError("'OPENMANO_TENANT' environment variable is not set")
239     return _get_item_uuid("tenants", tenant_name_id)
240
241 def _get_datacenter(datacenter_name_id = None, tenant = "any"):
242     if not datacenter_name_id:
243         datacenter_name_id = mano_datacenter
244         if not datacenter_name_id:
245             raise OpenmanoCLIError("neither 'OPENMANO_DATACENTER' environment variable is set nor --datacenter option is used")
246     return _get_item_uuid("datacenters", datacenter_name_id, tenant)
247
248 def vnf_create(args):
249     #print "vnf-create",args
250     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
251     tenant = _get_tenant()
252     myvnf = _load_file_or_yaml(args.file)
253
254     if args.name or args.description or args.image_path:
255         #print args.name
256         try:
257             if args.name:
258                 myvnf['vnf']['name'] = args.name
259             if args.description:
260                 myvnf['vnf']['description'] = args.description
261             if args.image_path:
262                 index=0
263                 for image_path_ in args.image_path.split(","):
264                     #print "image-path", image_path_
265                     myvnf['vnf']['VNFC'][index]['VNFC image']=image_path_
266                     index=index+1
267         except (KeyError, TypeError), e:
268             if str(e)=='vnf':           error_pos= "missing field 'vnf'"
269             elif str(e)=='name':        error_pos= "missing field  'vnf':'name'"
270             elif str(e)=='description': error_pos= "missing field  'vnf':'description'"
271             elif str(e)=='VNFC':        error_pos= "missing field  'vnf':'VNFC'"
272             elif str(e)==str(index):    error_pos= "field  'vnf':'VNFC' must be an array"
273             elif str(e)=='VNFC image':  error_pos= "missing field 'vnf':'VNFC'['VNFC image']"
274             else:                       error_pos="wrong format"
275             print "Wrong VNF descriptor: " + error_pos
276             return -1 
277     payload_req = json.dumps(myvnf)
278         
279     #print payload_req
280         
281     URLrequest = "http://%s:%s/openmano/%s/vnfs" %(mano_host, mano_port, tenant)
282     logger.debug("openmano request: %s", payload_req)
283     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
284     logger.debug("openmano response: %s", mano_response.text )
285
286     return _print_verbose(mano_response, args.verbose)
287
288 def vnf_list(args):
289     #print "vnf-list",args
290     if args.all:
291         tenant = "any"
292     else:
293         tenant = _get_tenant()
294     if args.name:
295         toshow = _get_item_uuid("vnfs", args.name, tenant)
296         URLrequest = "http://%s:%s/openmano/%s/vnfs/%s" %(mano_host, mano_port, tenant, toshow)
297     else:
298         URLrequest = "http://%s:%s/openmano/%s/vnfs" %(mano_host, mano_port, tenant)
299     mano_response = requests.get(URLrequest)
300     logger.debug("openmano response: %s", mano_response.text )
301     content = mano_response.json()
302     #print json.dumps(content, indent=4)
303     if args.verbose==None:
304         args.verbose=0
305     result = 0 if mano_response.status_code==200 else mano_response.status_code
306     if mano_response.status_code == 200:
307         if not args.name:
308             if args.verbose >= 3:
309                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
310                 return result
311             if len(content['vnfs']) == 0:
312                 print "No VNFs were found."
313                 return 404 #HTTP_Not_Found
314             for vnf in content['vnfs']:
315                 myoutput = "%s %s" %(vnf['uuid'].ljust(38),vnf['name'].ljust(20))
316                 if args.verbose >=1:
317                     myoutput = "%s %s" %(myoutput, vnf['created_at'].ljust(20))
318                 print myoutput
319                 if args.verbose >=2:
320                     print "  Description: %s" %vnf['description']
321                     print "  VNF descriptor file: %s" %vnf['path']
322         else:
323             if args.verbose:
324                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
325                 return result
326             vnf = content['vnf']
327             print "%s %s %s" %(vnf['uuid'].ljust(38),vnf['name'].ljust(20), vnf['created_at'].ljust(20))
328             print "  Description: %s" %vnf['description']
329             #print "  VNF descriptor file: %s" %vnf['path']
330             print "    VMs:"
331             for vm in vnf['VNFC']:
332                 #print "    %s %s %s" %(vm['name'].ljust(20), vm['uuid'].ljust(38), vm['description'].ljust(30))
333                 print "        %s %s" %(vm['name'].ljust(20), vm['description'])
334             if len(vnf['nets'])>0:
335                 print "    Internal nets:"
336                 for net in vnf['nets']:
337                     print "        %s %s" %(net['name'].ljust(20), net['description'])
338             if len(vnf['external-connections'])>0:
339                 print "    External interfaces:"
340                 for interface in vnf['external-connections']:
341                     print "        %s %s %s %s" %(interface['external_name'].ljust(20), interface['vm_name'].ljust(20), interface['internal_name'].ljust(20), \
342                                                   interface['vpci'].ljust(14))
343     else:
344         print content['error']['description']
345         if args.verbose:
346             print yaml.safe_dump(content, indent=4, default_flow_style=False)
347     return result
348
349 def vnf_delete(args):
350     #print "vnf-delete",args
351     if args.all:
352         tenant = "any"
353     else:
354         tenant = _get_tenant()
355     todelete = _get_item_uuid("vnfs", args.name, tenant=tenant)
356     if not args.force:
357         r = raw_input("Delete VNF %s (y/N)? " %(todelete))
358         if  not (len(r)>0  and r[0].lower()=="y"):
359             return 0
360     URLrequest = "http://%s:%s/openmano/%s/vnfs/%s" %(mano_host, mano_port, tenant, todelete)
361     mano_response = requests.delete(URLrequest)
362     logger.debug("openmano response: %s", mano_response.text )
363     result = 0 if mano_response.status_code==200 else mano_response.status_code
364     content = mano_response.json()
365     #print json.dumps(content, indent=4)
366     if mano_response.status_code == 200:
367         print content['result']
368     else:
369         print content['error']['description']
370     return result
371
372 def scenario_create(args):
373     #print "scenario-create",args
374     tenant = _get_tenant()
375     headers_req = {'content-type': 'application/yaml'}
376     myscenario = _load_file_or_yaml(args.file)
377
378     if args.name:
379         myscenario['name'] = args.name
380     if args.description:
381         myscenario['description'] = args.description
382     payload_req = yaml.safe_dump(myscenario, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
383     
384     #print payload_req
385         
386     URLrequest = "http://%s:%s/openmano/%s/scenarios" %(mano_host, mano_port, tenant)
387     logger.debug("openmano request: %s", payload_req)
388     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
389     logger.debug("openmano response: %s", mano_response.text )
390     return _print_verbose(mano_response, args.verbose)
391
392 def scenario_list(args):
393     #print "scenario-list",args
394     if args.all:
395         tenant = "any"
396     else:
397         tenant = _get_tenant()
398     if args.name:
399         toshow = _get_item_uuid("scenarios", args.name, tenant)
400         URLrequest = "http://%s:%s/openmano/%s/scenarios/%s" %(mano_host, mano_port, tenant, toshow)
401     else:
402         URLrequest = "http://%s:%s/openmano/%s/scenarios" %(mano_host, mano_port, tenant)
403     mano_response = requests.get(URLrequest)
404     logger.debug("openmano response: %s", mano_response.text )
405     content = mano_response.json()
406     #print json.dumps(content, indent=4)
407     if args.verbose==None:
408         args.verbose=0
409
410     result = 0 if mano_response.status_code==200 else mano_response.status_code
411     if mano_response.status_code == 200:
412         if not args.name:
413             if args.verbose >= 3:
414                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
415                 return result
416             if len(content['scenarios']) == 0:
417                 print "No scenarios were found."
418                 return 404 #HTTP_Not_Found
419             for scenario in content['scenarios']:
420                 myoutput = "%s %s" %(scenario['uuid'].ljust(38),scenario['name'].ljust(20))
421                 if args.verbose >=1:
422                     myoutput = "%s %s" %(myoutput, scenario['created_at'].ljust(20))
423                 print myoutput
424                 if args.verbose >=2:
425                     print "  Description: %s" %scenario['description']
426         else:
427             if args.verbose:
428                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
429                 return result
430             scenario = content['scenario']
431             myoutput = "%s %s %s" %(scenario['uuid'].ljust(38),scenario['name'].ljust(20), scenario['created_at'].ljust(20))
432             print myoutput
433             print "  Description: %s" %scenario['description']
434             print "    VNFs:"
435             for vnf in scenario['vnfs']:
436                 print "        %s %s %s" %(vnf['name'].ljust(20), vnf['vnf_id'].ljust(38), vnf['description'])
437             if len(scenario['nets'])>0:
438                 print "    Internal nets:"
439                 for net in scenario['nets']:
440                     if net['description'] is None:   #if description does not exist, description is "-". Valid for external and internal nets.
441                         net['description'] = '-' 
442                     if not net['external']:
443                         print "        %s %s %s" %(net['name'].ljust(20), net['uuid'].ljust(38), net['description'].ljust(30))
444                 print "    External nets:"
445                 for net in scenario['nets']:
446                     if net['external']:
447                         print "        %s %s %s vim-id:%s" %(net['name'].ljust(20), net['uuid'].ljust(38), net['description'].ljust(30), net['vim_id'])
448     else:
449         print content['error']['description']
450         if args.verbose:
451             print yaml.safe_dump(content, indent=4, default_flow_style=False)
452     return result
453
454 def scenario_delete(args):
455     #print "scenario-delete",args
456     if args.all:
457         tenant = "any"
458     else:
459         tenant = _get_tenant()
460     todelete = _get_item_uuid("scenarios", args.name, tenant=tenant)
461     if not args.force:
462         r = raw_input("Delete scenario %s (y/N)? " %(args.name))
463         if  not (len(r)>0  and r[0].lower()=="y"):
464             return 0
465     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s" %(mano_host, mano_port, tenant, todelete)
466     mano_response = requests.delete(URLrequest)
467     logger.debug("openmano response: %s", mano_response.text )
468     result = 0 if mano_response.status_code==200 else mano_response.status_code
469     content = mano_response.json()
470     #print json.dumps(content, indent=4)
471     if mano_response.status_code == 200:
472         print content['result']
473     else:
474         print content['error']['description']
475     return result
476
477 def scenario_deploy(args):
478     print "This command is deprecated, use 'openmano instance-scenario-create --scenario %s --name %s' instead!!!" % (args.scenario, args.name)
479     print
480     args.file = None
481     args.netmap_use = None
482     args.netmap_create = None
483     args.keypair = None
484     args.keypair_auto = None
485     return instance_create(args)
486
487 #     #print "scenario-deploy",args
488 #     headers_req = {'content-type': 'application/json'}
489 #     action = {}
490 #     actionCmd="start"
491 #     if args.nostart:
492 #         actionCmd="reserve"
493 #     action[actionCmd] = {}
494 #     action[actionCmd]["instance_name"] = args.name
495 #     if args.datacenter != None:
496 #         action[actionCmd]["datacenter"] = args.datacenter
497 #     elif mano_datacenter != None:
498 #         action[actionCmd]["datacenter"] = mano_datacenter
499 #         
500 #     if args.description:
501 #         action[actionCmd]["description"] = args.description
502 #     payload_req = json.dumps(action, indent=4)
503 #     #print payload_req
504
505 #     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, mano_tenant, args.scenario)
506 #     logger.debug("openmano request: %s", payload_req)
507 #     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
508 #     logger.debug("openmano response: %s", mano_response.text )
509 #     if args.verbose==None:
510 #         args.verbose=0
511 #     
512 #     result = 0 if mano_response.status_code==200 else mano_response.status_code
513 #     content = mano_response.json()
514 #     #print json.dumps(content, indent=4)
515 #     if args.verbose >= 3:
516 #         print yaml.safe_dump(content, indent=4, default_flow_style=False)
517 #         return result
518
519 #     if mano_response.status_code == 200:
520 #         myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
521 #         if args.verbose >=1:
522 #             myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
523 #         if args.verbose >=2:
524 #             myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
525 #         print myoutput
526 #         print ""
527 #         print "To check the status, run the following command:"
528 #         print "openmano instance-scenario-list <instance_id>"
529 #     else:
530 #         print content['error']['description']
531 #     return result
532
533 def scenario_verify(args):
534     #print "scenario-verify",args
535     headers_req = {'content-type': 'application/json'}
536     action = {}
537     action["verify"] = {}
538     action["verify"]["instance_name"] = "scen-verify-return5"
539     payload_req = json.dumps(action, indent=4)
540     #print payload_req
541
542     URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, mano_tenant, args.scenario)
543     logger.debug("openmano request: %s", payload_req)
544     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
545     logger.debug("openmano response: %s", mano_response.text )
546     
547     result = 0 if mano_response.status_code==200 else mano_response.status_code
548     content = mano_response.json()
549     #print json.dumps(content, indent=4)
550     if mano_response.status_code == 200:
551         print content['result']
552     else:
553         print content['error']['description']
554     return result
555
556 def instance_create(args):
557     tenant = _get_tenant()
558     headers_req = {'content-type': 'application/yaml'}
559     myInstance={"instance": {}, "schema_version": "0.1"}
560     if args.file:
561         instance_dict = _load_file_or_yaml(args.file)
562         if "instance" not in instance_dict:
563             myInstance = {"instance": instance_dict, "schema_version": "0.1"}
564         else:
565             myInstance = instance_dict
566     if args.name:
567         myInstance["instance"]['name'] = args.name
568     if args.description:
569         myInstance["instance"]['description'] = args.description
570     if args.nostart:
571         myInstance["instance"]['action'] = "reserve"
572     #datacenter
573     datacenter = myInstance["instance"].get("datacenter")
574     if args.datacenter != None:
575         datacenter = args.datacenter
576     myInstance["instance"]["datacenter"] = _get_datacenter(datacenter, tenant)
577     #scenario
578     scenario = myInstance["instance"].get("scenario")
579     if args.scenario != None:
580         scenario = args.scenario
581     if not scenario:
582         print "you must provide a scenario in the file descriptor or with --scenario"
583         return -1
584     myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
585     if args.netmap_use:
586         if "networks" not in myInstance["instance"]:
587             myInstance["instance"]["networks"] = {}
588         for net in args.netmap_use:
589             net_comma_list = net.split(",")
590             for net_comma in net_comma_list:
591                 net_tuple = net_comma.split("=")
592                 if len(net_tuple) != 2:
593                     print "error at netmap-use. Expected net-scenario=net-datacenter. (%s)?" % net_comma
594                     return
595                 net_scenario   = net_tuple[0].strip()
596                 net_datacenter = net_tuple[1].strip()
597                 if net_scenario not in myInstance["instance"]["networks"]:
598                     myInstance["instance"]["networks"][net_scenario] = {} 
599                 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
600                     myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
601                 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-use"] = net_datacenter
602     if args.netmap_create:
603         if "networks" not in myInstance["instance"]:
604             myInstance["instance"]["networks"] = {}
605         for net in args.netmap_create:
606             net_comma_list = net.split(",")
607             for net_comma in net_comma_list:
608                 net_tuple = net_comma.split("=")
609                 if len(net_tuple) == 1:
610                     net_scenario   = net_tuple[0].strip()
611                     net_datacenter = None
612                 elif len(net_tuple) == 2:
613                     net_scenario   = net_tuple[0].strip()
614                     net_datacenter = net_tuple[1].strip()
615                 else:
616                     print "error at netmap-create. Expected net-scenario=net-datacenter or net-scenario. (%s)?" % net_comma
617                     return
618                 if net_scenario not in myInstance["instance"]["networks"]:
619                     myInstance["instance"]["networks"][net_scenario] = {} 
620                 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
621                     myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
622                 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-create"] = net_datacenter
623     if args.keypair:
624         if "cloud-config" not in myInstance["instance"]:
625             myInstance["instance"]["cloud-config"] = {}
626         cloud_config = myInstance["instance"]["cloud-config"]
627         for key in args.keypair:
628             index = key.find(":")
629             if index<0:
630                 if "key-pairs" not in cloud_config:
631                     cloud_config["key-pairs"] = []
632                 cloud_config["key-pairs"].append(key)
633             else:
634                 user = key[:index]
635                 key_ = key[index+1:]
636                 key_list = key_.split(",")
637                 if "users" not in cloud_config:
638                     cloud_config["users"] = []
639                 cloud_config["users"].append({"name": user, "key-pairs": key_list  })
640     if args.keypair_auto:
641         try:
642             keys=[]
643             home = os.getenv("HOME")
644             user = os.getenv("USER")
645             files = os.listdir(home+'/.ssh')
646             for file in files:
647                 if file[-4:] == ".pub":
648                     with open(home+'/.ssh/'+file, 'r') as f:
649                         keys.append(f.read())
650             if not keys:
651                 print "Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh')
652                 return 1
653         except Exception as e:
654             print "Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e))
655             return 1
656         
657         if "cloud-config" not in myInstance["instance"]:
658             myInstance["instance"]["cloud-config"] = {}
659         cloud_config = myInstance["instance"]["cloud-config"]
660         if "key-pairs" not in cloud_config:
661             cloud_config["key-pairs"] = []
662         if user:
663             if "users" not in cloud_config:
664                 cloud_config["users"] = []
665             cloud_config["users"].append({"name": user, "key-pairs": keys })                    
666                         
667     payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
668     logger.debug("openmano request: %s", payload_req)
669     URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
670     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
671     logger.debug("openmano response: %s", mano_response.text )
672     if args.verbose==None:
673         args.verbose=0
674     
675     result = 0 if mano_response.status_code==200 else mano_response.status_code
676     content = mano_response.json()
677     #print json.dumps(content, indent=4)
678     if args.verbose >= 3:
679         print yaml.safe_dump(content, indent=4, default_flow_style=False)
680         return result
681
682     if mano_response.status_code == 200:
683         myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
684         if args.verbose >=1:
685             myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
686         if args.verbose >=2:
687             myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
688         print myoutput
689     else:
690         print content['error']['description']
691     return result
692
693 def instance_scenario_list(args):
694     #print "instance-scenario-list",args
695     if args.all:
696         tenant = "any"
697     else:
698         tenant = _get_tenant()
699     if args.name:
700         toshow = _get_item_uuid("instances", args.name, tenant)
701         URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, toshow)
702     else:
703         URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
704     mano_response = requests.get(URLrequest)
705     logger.debug("openmano response: %s", mano_response.text )
706     content = mano_response.json()
707     #print json.dumps(content, indent=4)
708     if args.verbose==None:
709         args.verbose=0
710
711     result = 0 if mano_response.status_code==200 else mano_response.status_code
712     if mano_response.status_code == 200:
713         if not args.name:
714             if args.verbose >= 3:
715                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
716                 return result
717             if len(content['instances']) == 0:
718                 print "No scenario instances were found."
719                 return result
720             for instance in content['instances']:
721                 myoutput = "%s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20))
722                 if args.verbose >=1:
723                     myoutput = "%s %s" %(myoutput, instance['created_at'].ljust(20))
724                 print myoutput
725                 if args.verbose >=2:
726                     print "Description: %s" %instance['description']
727         else:
728             if args.verbose:
729                 print yaml.safe_dump(content, indent=4, default_flow_style=False)
730                 return result
731             instance = content
732             print "%s %s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20),instance['created_at'].ljust(20))
733             print "Description: %s" %instance['description']
734             print "Template scenario id: %s" %instance['scenario_id']
735             print "Template scenario name: %s" %instance['scenario_name']
736             print "---------------------------------------"
737             print "VNF instances: %d" %len(instance['vnfs'])
738             for vnf in instance['vnfs']:
739                 #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))
740                 print "    %s %s Template vnf id: %s" %(vnf['uuid'].ljust(38), vnf['vnf_name'].ljust(20), vnf['vnf_id'].ljust(38))
741             if len(instance['nets'])>0:
742                 print "---------------------------------------"
743                 print "Internal nets:"
744                 for net in instance['nets']:
745                     if net['created']:
746                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
747                 print "---------------------------------------"
748                 print "External nets:"
749                 for net in instance['nets']:
750                     if not net['created']:
751                         print "    %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
752             print "---------------------------------------"
753             print "VM instances:"
754             for vnf in instance['vnfs']:
755                 for vm in vnf['vms']:
756                     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'])
757     else:
758         print content['error']['description']
759         if args.verbose:
760             print yaml.safe_dump(content, indent=4, default_flow_style=False)
761     return result
762
763 def instance_scenario_status(args):
764     print "instance-scenario-status"
765     return 0
766
767 def instance_scenario_delete(args):
768     if args.all:
769         tenant = "any"
770     else:
771         tenant = _get_tenant()
772     todelete = _get_item_uuid("instances", args.name, tenant=tenant)
773     #print "instance-scenario-delete",args
774     if not args.force:
775         r = raw_input("Delete scenario instance %s (y/N)? " %(args.name))
776         if  not (len(r)>0  and r[0].lower()=="y"):
777             return
778     URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, todelete)
779     mano_response = requests.delete(URLrequest)
780     logger.debug("openmano response: %s", mano_response.text )
781     result = 0 if mano_response.status_code==200 else mano_response.status_code
782     content = mano_response.json()
783     #print json.dumps(content, indent=4)
784     if mano_response.status_code == 200:
785         print content['result']
786     else:
787         print content['error']['description']
788     return result
789
790 def instance_scenario_action(args):
791     #print "instance-scenario-action", args
792     tenant = _get_tenant()
793     toact = _get_item_uuid("instances", args.name, tenant=tenant)
794     action={}
795     action[ args.action ] = args.param
796     if args.vnf:
797         action["vnfs"] = args.vnf
798     if args.vm:
799         action["vms"] = args.vm
800     
801     headers_req = {'content-type': 'application/json'}
802     payload_req = json.dumps(action, indent=4)
803     URLrequest = "http://%s:%s/openmano/%s/instances/%s/action" %(mano_host, mano_port, tenant, toact)
804     logger.debug("openmano request: %s", payload_req)
805     mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
806     logger.debug("openmano response: %s", mano_response.text )
807     result = 0 if mano_response.status_code==200 else mano_response.status_code
808     content = mano_response.json()
809     #print json.dumps(content, indent=4)
810     if mano_response.status_code == 200:
811         if args.verbose:
812             print yaml.safe_dump(content, indent=4, default_flow_style=False)
813             return result
814         for uuid,c in content.iteritems():
815             print "%s %s %s" %(uuid.ljust(38), c['name'].ljust(20),c['description'].ljust(20))
816     else:
817         print content['error']['description']
818     return result
819
820
821 def instance_vnf_list(args):
822     print "instance-vnf-list"
823     return 0
824
825 def instance_vnf_status(args):
826     print "instance-vnf-status"
827     return 0
828
829 def tenant_create(args):
830     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
831     tenant_dict={"name": args.name}
832     if args.description!=None:
833         tenant_dict["description"] = args.description 
834     payload_req = json.dumps( {"tenant": tenant_dict })
835     
836     #print payload_req
837         
838     URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
839     logger.debug("openmano request: %s", payload_req)
840     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
841     logger.debug("openmano response: %s", mano_response.text )
842     return _print_verbose(mano_response, args.verbose)
843
844 def tenant_list(args):
845     #print "tenant-list",args
846     if args.name:
847         toshow = _get_item_uuid("tenants", args.name)
848         URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, toshow)
849     else:
850         URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
851     mano_response = requests.get(URLrequest)
852     logger.debug("openmano response: %s", mano_response.text )
853     if args.verbose==None:
854         args.verbose=0
855     if args.name!=None:
856         args.verbose += 1
857     return _print_verbose(mano_response, args.verbose)
858
859 def tenant_delete(args):
860     #print "tenant-delete",args
861     todelete = _get_item_uuid("tenants", args.name)
862     if not args.force:
863         r = raw_input("Delete tenant %s (y/N)? " %(args.name))
864         if  not (len(r)>0  and r[0].lower()=="y"):
865             return 0
866     URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, todelete)
867     mano_response = requests.delete(URLrequest)
868     logger.debug("openmano response: %s", mano_response.text )
869     result = 0 if mano_response.status_code==200 else mano_response.status_code
870     content = mano_response.json()
871     #print json.dumps(content, indent=4)
872     if mano_response.status_code == 200:
873         print content['result']
874     else:
875         print content['error']['description']
876     return result
877
878 def datacenter_attach(args):
879     tenant = _get_tenant()
880     datacenter = _get_datacenter(args.name)
881     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
882     
883     datacenter_dict={}
884     if args.vim_tenant_id != None:
885         datacenter_dict['vim_tenant'] = args.vim_tenant_id
886     if args.vim_tenant_name != None:
887         datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
888     if args.user != None:
889         datacenter_dict['vim_username'] = args.user
890     if args.password != None:
891         datacenter_dict['vim_password'] = args.password
892     if args.config!=None:
893         datacenter_dict["config"] = _load_file_or_yaml(args.config)
894     payload_req = json.dumps( {"datacenter": datacenter_dict })
895     
896     #print payload_req
897         
898     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
899     logger.debug("openmano request: %s", payload_req)
900     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
901     logger.debug("openmano response: %s", mano_response.text )
902     result = _print_verbose(mano_response, args.verbose)
903     #provide addional information if error
904     if mano_response.status_code != 200:
905         content = mano_response.json()
906         if "already in use for  'name'" in content['error']['description'] and \
907                 "to database vim_tenants table" in content['error']['description']:
908             print "Try to specify a different name with --vim-tenant-name"
909     return result
910
911 def datacenter_detach(args):
912     if args.all:
913         tenant = "any"
914     else:
915         tenant = _get_tenant()
916     datacenter = _get_datacenter(args.name, tenant)
917     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
918     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
919     mano_response = requests.delete(URLrequest, headers=headers_req)
920     logger.debug("openmano response: %s", mano_response.text )
921     content = mano_response.json()
922     #print json.dumps(content, indent=4)
923     result = 0 if mano_response.status_code==200 else mano_response.status_code
924     if mano_response.status_code == 200:
925         print content['result']
926     else:
927         print content['error']['description']
928     return result
929
930 def datacenter_create(args):
931     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
932     datacenter_dict={"name": args.name, "vim_url": args.url}
933     if args.description!=None:
934         datacenter_dict["description"] = args.description 
935     if args.type!=None:
936         datacenter_dict["type"] = args.type 
937     if args.url!=None:
938         datacenter_dict["vim_url_admin"] = args.url_admin 
939     if args.config!=None:
940         datacenter_dict["config"] = _load_file_or_yaml(args.config) 
941     payload_req = json.dumps( {"datacenter": datacenter_dict })
942     
943     #print payload_req
944         
945     URLrequest = "http://%s:%s/openmano/datacenters" %(mano_host, mano_port)
946     logger.debug("openmano request: %s", payload_req)
947     mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
948     logger.debug("openmano response: %s", mano_response.text )
949     return _print_verbose(mano_response, args.verbose)
950
951 def datacenter_delete(args):
952     #print "datacenter-delete",args
953     todelete = _get_item_uuid("datacenters", args.name, "any")
954     if not args.force:
955         r = raw_input("Delete datacenter %s (y/N)? " %(args.name))
956         if  not (len(r)>0  and r[0].lower()=="y"):
957             return 0
958     URLrequest = "http://%s:%s/openmano/datacenters/%s" %(mano_host, mano_port, todelete)
959     mano_response = requests.delete(URLrequest)
960     logger.debug("openmano response: %s", mano_response.text )
961     result = 0 if mano_response.status_code==200 else mano_response.status_code
962     content = mano_response.json()
963     #print json.dumps(content, indent=4)
964     if mano_response.status_code == 200:
965         print content['result']
966     else:
967         print content['error']['description']
968     return result
969
970 def datacenter_list(args):
971     #print "datacenter-list",args
972     tenant='any' if args.all else _get_tenant()
973     
974     if args.name:
975         toshow = _get_item_uuid("datacenters", args.name, tenant) 
976         URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, toshow)
977     else:
978         URLrequest = "http://%s:%s/openmano/%s/datacenters" %(mano_host, mano_port, tenant)
979     mano_response = requests.get(URLrequest)
980     logger.debug("openmano response: %s", mano_response.text )
981     if args.verbose==None:
982         args.verbose=0
983     if args.name!=None:
984         args.verbose += 1
985     return _print_verbose(mano_response, args.verbose)
986
987 def vim_action(args):
988     #print "datacenter-net-action",args
989     tenant = _get_tenant()
990     datacenter = _get_datacenter(args.datacenter, tenant)
991     if args.verbose==None:
992         args.verbose=0
993     if args.action=="list":
994         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
995         if args.name!=None:
996             args.verbose += 1
997             URLrequest += "/" + args.name
998         mano_response = requests.get(URLrequest)
999         logger.debug("openmano response: %s", mano_response.text )
1000         return _print_verbose(mano_response, args.verbose)
1001     elif args.action=="delete":
1002         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss/%s" %(mano_host, mano_port, tenant, datacenter, args.item, args.name)
1003         mano_response = requests.delete(URLrequest)
1004         logger.debug("openmano response: %s", mano_response.text )
1005         result = 0 if mano_response.status_code==200 else mano_response.status_code
1006         content = mano_response.json()
1007         #print json.dumps(content, indent=4)
1008         if mano_response.status_code == 200:
1009             print content['result']
1010         else:
1011             print content['error']['description']
1012         return result
1013     elif args.action=="create":
1014         headers_req = {'content-type': 'application/yaml'}
1015         if args.file:
1016             create_dict = _load_file_or_yaml(args.file)
1017             if args.item not in create_dict:
1018                 create_dict = {args.item: create_dict}
1019         else:
1020             create_dict = {args.item:{}}
1021         if args.name:
1022             create_dict[args.item]['name'] = args.name
1023         #if args.description:
1024         #    create_dict[args.item]['description'] = args.description
1025         if args.item=="vim-net":
1026             if args.bind_net:
1027                 create_dict[args.item]['bind_net'] = args.bind_net
1028             if args.bind_type:
1029                 create_dict[args.item]['bind_type'] = args.bind_type
1030             if args.shared:
1031                 create_dict[args.item]['shared'] = args.shared
1032         if "name" not in create_dict[args.item]:
1033             print "You must provide a name in the descriptor file or with the --name option"
1034             return
1035         payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
1036         logger.debug("openmano request: %s", payload_req)
1037         URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, mano_tenant, datacenter, args.item)
1038         mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
1039         logger.debug("openmano response: %s", mano_response.text )
1040         if args.verbose==None:
1041             args.verbose=0
1042         return _print_verbose(mano_response, args.verbose)
1043
1044
1045 def datacenter_net_action(args):
1046     if args.action == "net-update":
1047         print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-import' instead!!!"
1048         print
1049         args.action = "netmap-delete"
1050         args.netmap = None
1051         args.all = True
1052         r = datacenter_netmap_action(args)
1053         if r == 0:
1054             args.force = True
1055             args.action = "netmap-import"
1056             r = datacenter_netmap_action(args)
1057         return r
1058
1059     if args.action == "net-edit":
1060         args.netmap = args.net
1061         args.name = None
1062     elif args.action == "net-list":
1063         args.netmap = None
1064     elif args.action == "net-delete":
1065         args.netmap = args.net
1066         args.all = False
1067           
1068     args.action = "netmap" + args.action[3:]
1069     args.vim_name=None
1070     args.vim_id=None
1071     print "This command is deprecated, use 'openmano datacenter-%s' instead!!!" % args.action
1072     print
1073     return datacenter_netmap_action(args)
1074
1075 def datacenter_netmap_action(args):
1076     tenant = _get_tenant()
1077     datacenter = _get_datacenter(args.datacenter, tenant)
1078     #print "datacenter_netmap_action",args
1079     payload_req = None
1080     if args.verbose==None:
1081         args.verbose=0
1082     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1083     URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/netmaps" %(mano_host, mano_port, tenant, datacenter)
1084         
1085     if args.action=="netmap-list":
1086         if args.netmap:
1087             URLrequest += "/" + args.netmap
1088             args.verbose += 1
1089         mano_response = requests.get(URLrequest)
1090             
1091     elif args.action=="netmap-delete":
1092         if args.netmap and args.all:
1093             print "you can not use a netmap name and the option --all at the same time"
1094             return 1
1095         if args.netmap:
1096             force_text= "Delete default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter)
1097             URLrequest += "/" + args.netmap
1098         elif args.all: 
1099             force_text="Delete all default netmaps from datacenter '%s' (y/N)? " % (datacenter)
1100         else:
1101             print "you must specify a netmap name or the option --all"
1102             return 1
1103         if not args.force:
1104             r = raw_input(force_text)
1105             if  len(r)>0  and r[0].lower()=="y":
1106                 pass
1107             else:
1108                 return 0
1109         mano_response = requests.delete(URLrequest, headers=headers_req)
1110     elif args.action=="netmap-import":
1111         if not args.force:
1112             r = raw_input("Create all the available networks from datacenter '%s' as default netmaps (y/N)? " % (datacenter))
1113             if  len(r)>0  and r[0].lower()=="y":
1114                 pass
1115             else:
1116                 return 0
1117         URLrequest += "/upload"
1118         mano_response = requests.post(URLrequest, headers=headers_req)
1119     elif args.action=="netmap-edit" or args.action=="netmap-create":
1120         if args.file:
1121             payload = _load_file_or_yaml(args.file)
1122         else:
1123             payload = {}
1124         if "netmap" not in payload:
1125             payload = {"netmap": payload}
1126         if args.name:
1127             payload["netmap"]["name"] = args.name
1128         if args.vim_id:
1129             payload["netmap"]["vim_id"] = args.vim_id
1130         if args.action=="netmap-create" and args.vim_name:
1131             payload["netmap"]["vim_name"] = args.vim_name
1132         payload_req = json.dumps(payload)
1133         logger.debug("openmano request: %s", payload_req)
1134         
1135         if args.action=="netmap-edit" and not args.force:
1136             if len(payload["netmap"]) == 0:
1137                 print "You must supply some parameter to edit"
1138                 return 1
1139             r = raw_input("Edit default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter))
1140             if  len(r)>0  and r[0].lower()=="y":
1141                 pass
1142             else:
1143                 return 0
1144             URLrequest += "/" + args.netmap
1145             mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1146         else: #netmap-create
1147             if "vim_name" not in payload["netmap"] and "vim_id" not in payload["netmap"]:
1148                 print "You must supply either --vim-id or --vim-name option; or include one of them in the file descriptor"
1149                 return 1
1150             mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1151
1152     logger.debug("openmano response: %s", mano_response.text )
1153     return _print_verbose(mano_response, args.verbose)
1154
1155 def element_edit(args):
1156     element = _get_item_uuid(args.element, args.name)
1157     headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1158     URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, args.element, element)
1159     payload=_load_file_or_yaml(args.file)
1160     if args.element[:-1] not in payload:
1161         payload = {args.element[:-1]: payload }
1162     payload_req = json.dumps(payload)
1163     
1164     #print payload_req
1165     if not args.force or (args.name==None and args.filer==None):
1166         r = raw_input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
1167         if  len(r)>0  and r[0].lower()=="y":
1168             pass
1169         else:
1170             return 0
1171     logger.debug("openmano request: %s", payload_req)
1172     mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1173     logger.debug("openmano response: %s", mano_response.text )
1174     if args.verbose==None:
1175         args.verbose=0
1176     if args.name!=None:
1177         args.verbose += 1
1178     return _print_verbose(mano_response, args.verbose)
1179
1180
1181 global mano_host
1182 global mano_port
1183 global mano_tenant
1184
1185 if __name__=="__main__":
1186     
1187     mano_tenant = os.getenv('OPENMANO_TENANT', None)
1188     mano_host = os.getenv('OPENMANO_HOST',"localhost")
1189     mano_port = os.getenv('OPENMANO_PORT',"9090")
1190     mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
1191     
1192     main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
1193     main_parser.add_argument('--version', action='version', version='%(prog)s ' + __version__ )
1194     
1195     subparsers = main_parser.add_subparsers(help='commands')
1196     
1197     parent_parser = argparse.ArgumentParser(add_help=False)
1198     parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
1199     parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1200
1201     config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
1202     config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
1203     config_parser.set_defaults(func=config)
1204
1205     vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
1206     vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
1207     vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1208     vnf_create_parser.add_argument("--description", action="store", help="description of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1209     vnf_create_parser.add_argument("--image-path", action="store",  help="change image path locations (overwritten)")
1210     vnf_create_parser.set_defaults(func=vnf_create)
1211
1212     vnf_list_parser = subparsers.add_parser('vnf-list', parents=[parent_parser], help="lists information about a vnf")
1213     vnf_list_parser.add_argument("name", nargs='?', help="name of the VNF")
1214     vnf_list_parser.add_argument("-a", "--all", action="store_true", help="shows all vnfs, not only the owned or public ones")
1215     #vnf_list_parser.add_argument('--descriptor', help="prints the VNF descriptor", action="store_true")
1216     vnf_list_parser.set_defaults(func=vnf_list)
1217     
1218     vnf_delete_parser = subparsers.add_parser('vnf-delete', parents=[parent_parser], help="deletes a vnf from the catalogue")
1219     vnf_delete_parser.add_argument("name", action="store", help="name or uuid of the VNF to be deleted")
1220     vnf_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1221     vnf_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1222     vnf_delete_parser.set_defaults(func=vnf_delete)
1223     
1224     scenario_create_parser = subparsers.add_parser('scenario-create', parents=[parent_parser], help="adds a scenario into the OPENMANO DB")
1225     scenario_create_parser.add_argument("file", action="store", help="location of the YAML file describing the scenario").completer = FilesCompleter
1226     scenario_create_parser.add_argument("--name", action="store", help="name of the scenario (if it exists in the YAML scenario, it is overwritten)")
1227     scenario_create_parser.add_argument("--description", action="store", help="description of the scenario (if it exists in the YAML scenario, it is overwritten)")
1228     scenario_create_parser.set_defaults(func=scenario_create)
1229
1230     scenario_list_parser = subparsers.add_parser('scenario-list', parents=[parent_parser], help="lists information about a scenario")
1231     scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario")
1232     #scenario_list_parser.add_argument('--descriptor', help="prints the scenario descriptor", action="store_true")
1233     scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all scenarios, not only the owned or public ones")
1234     scenario_list_parser.set_defaults(func=scenario_list)
1235     
1236     scenario_delete_parser = subparsers.add_parser('scenario-delete', parents=[parent_parser], help="deletes a scenario from the OPENMANO DB")
1237     scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario to be deleted")
1238     scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1239     scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1240     scenario_delete_parser.set_defaults(func=scenario_delete)
1241
1242     scenario_deploy_parser = subparsers.add_parser('scenario-deploy', parents=[parent_parser], help="deploys a scenario")
1243     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be deployed")
1244     scenario_deploy_parser.add_argument("name", action="store", help="name of the instance")
1245     scenario_deploy_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1246     scenario_deploy_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1247     scenario_deploy_parser.add_argument("--description", action="store", help="description of the instance")
1248     scenario_deploy_parser.set_defaults(func=scenario_deploy)
1249     
1250     scenario_deploy_parser = subparsers.add_parser('scenario-verify', help="verifies if a scenario can be deployed (deploys it and deletes it)")
1251     scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be verified")
1252     scenario_deploy_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1253     scenario_deploy_parser.set_defaults(func=scenario_verify)
1254     
1255     instance_scenario_create_parser = subparsers.add_parser('instance-scenario-create', parents=[parent_parser], help="deploys a scenario")
1256     instance_scenario_create_parser.add_argument("file", nargs='?', help="descriptor of the instance. Must be a file or yaml/json text")
1257     instance_scenario_create_parser.add_argument("--scenario", action="store", help="name or uuid of the scenario to be deployed")
1258     instance_scenario_create_parser.add_argument("--name", action="store", help="name of the instance")
1259     instance_scenario_create_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1260     instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1261     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")
1262     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")
1263     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")
1264     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")
1265     instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
1266     instance_scenario_create_parser.set_defaults(func=instance_create)
1267
1268     instance_scenario_list_parser = subparsers.add_parser('instance-scenario-list', parents=[parent_parser], help="lists information about a scenario instance")
1269     instance_scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario instance")
1270     instance_scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all instance-scenarios, not only the owned")
1271     instance_scenario_list_parser.set_defaults(func=instance_scenario_list)
1272
1273     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)")
1274     instance_scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario instance to be deleted")
1275     instance_scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1276     instance_scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1277     instance_scenario_delete_parser.set_defaults(func=instance_scenario_delete)
1278     
1279     instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
1280     instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1281     instance_scenario_action_parser.add_argument("action", action="store", type=str, \
1282             choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console"],\
1283             help="action to send")
1284     instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console type (novnc, ...), reboot type (TODO)")
1285     instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
1286     instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
1287     instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
1288
1289     #instance_scenario_status_parser = subparsers.add_parser('instance-scenario-status', help="show the status of a scenario instance")
1290     #instance_scenario_status_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1291     #instance_scenario_status_parser.set_defaults(func=instance_scenario_status)
1292     
1293     tenant_create_parser = subparsers.add_parser('tenant-create', parents=[parent_parser], help="creates a new tenant")
1294     tenant_create_parser.add_argument("name", action="store", help="name for the tenant")
1295     tenant_create_parser.add_argument("--description", action="store", help="description of the tenant")
1296     tenant_create_parser.set_defaults(func=tenant_create)
1297
1298     tenant_delete_parser = subparsers.add_parser('tenant-delete', parents=[parent_parser], help="deletes a tenant from the catalogue")
1299     tenant_delete_parser.add_argument("name", action="store", help="name or uuid of the tenant to be deleted")
1300     tenant_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1301     tenant_delete_parser.set_defaults(func=tenant_delete)
1302
1303     tenant_list_parser = subparsers.add_parser('tenant-list', parents=[parent_parser], help="lists information about a tenant")
1304     tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
1305     tenant_list_parser.set_defaults(func=tenant_list)
1306
1307     item_list=('tenant','datacenter') #put tenant before so that help appear in order
1308     for item in item_list:
1309         element_edit_parser = subparsers.add_parser(item+'-edit', parents=[parent_parser], help="edits one "+item)
1310         element_edit_parser.add_argument("name", help="name or uuid of the "+item)
1311         element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1312         element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1313         element_edit_parser.set_defaults(func=element_edit, element=item + 's')
1314
1315     datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
1316     datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
1317     datacenter_create_parser.add_argument("url", action="store", help="url for the datacenter")
1318     datacenter_create_parser.add_argument("--url_admin", action="store", help="url for administration for the datacenter")
1319     datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
1320     datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1321     datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
1322     datacenter_create_parser.set_defaults(func=datacenter_create)
1323
1324     datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
1325     datacenter_delete_parser.add_argument("name", action="store", help="name or uuid of the datacenter to be deleted")
1326     datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1327     datacenter_delete_parser.set_defaults(func=datacenter_delete)
1328
1329     datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
1330     datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
1331     datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
1332     datacenter_list_parser.set_defaults(func=datacenter_list)
1333
1334     datacenter_attach_parser = subparsers.add_parser('datacenter-attach', parents=[parent_parser], help="associates a datacenter to the operating tenant")
1335     datacenter_attach_parser.add_argument("name", help="name or uuid of the datacenter")
1336     datacenter_attach_parser.add_argument('--vim-tenant-id', action='store', help="specify a datacenter tenant to use. A new one is created by default")
1337     datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1338     datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1339     datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1340     datacenter_attach_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1341     datacenter_attach_parser.set_defaults(func=datacenter_attach)
1342
1343     datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
1344     datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
1345     datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
1346     datacenter_detach_parser.set_defaults(func=datacenter_detach)
1347
1348
1349     action_dict={'net-update': 'retrieves external networks from datacenter',
1350                  'net-edit': 'edits an external network',
1351                  'net-delete': 'deletes an external network',
1352                  'net-list': 'lists external networks from a datacenter'
1353                  }
1354     for item in action_dict:
1355         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1356         datacenter_action_parser.add_argument("datacenter", help="name or uuid of the datacenter")
1357         if item=='net-edit' or item=='net-delete':
1358             datacenter_action_parser.add_argument("net", help="name or uuid of the datacenter net")
1359         if item=='net-edit':
1360             datacenter_action_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1361         if item!='net-list':
1362             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1363         datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
1364
1365
1366     action_dict={'netmap-import': 'create network senario netmap base on the datacenter networks',
1367                  'netmap-create': 'create a new network senario netmap',
1368                  'netmap-edit':   'edit name of a network senario netmap',
1369                  'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
1370                  'netmap-list':   'list/show network scenario netmaps'
1371                  }
1372     for item in action_dict:
1373         datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1374         datacenter_action_parser.add_argument("--datacenter", help="name or uuid of the datacenter")
1375         #if item=='net-add':
1376         #    datacenter_action_parser.add_argument("net", help="name of the network")
1377         if item=='netmap-delete':
1378             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to delete")
1379             datacenter_action_parser.add_argument("--all", action="store_true", help="delete all netmap of this datacenter")
1380             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1381         if item=='netmap-edit':
1382             datacenter_action_parser.add_argument("netmap", help="name or uuid of the datacenter netmap do edit")
1383             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file with the changes").completer = FilesCompleter
1384             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap")
1385             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1386             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1387         if item=='netmap-list':
1388             datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to show")
1389         if item=='netmap-create':
1390             datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file descriptor with the changes").completer = FilesCompleter
1391             datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
1392             datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1393             datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
1394         if item=='netmap-import':
1395             datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1396         datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)
1397     
1398     for item in ("network", "tenant"):
1399         if item=="network":
1400             commnad_name = 'vim-net'
1401         else:
1402             commnad_name = 'vim-'+item
1403         vim_item_list_parser = subparsers.add_parser(commnad_name + '-list', parents=[parent_parser], help="list the vim " + item + "s")
1404         vim_item_list_parser.add_argument("name", nargs='?', help="name or uuid of the " + item + "s")
1405         vim_item_list_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1406         vim_item_list_parser.set_defaults(func=vim_action, item=item, action="list")
1407
1408         vim_item_del_parser = subparsers.add_parser(commnad_name + '-delete', parents=[parent_parser], help="list the vim " + item + "s")
1409         vim_item_del_parser.add_argument("name", help="name or uuid of the " + item + "s")
1410         vim_item_del_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1411         vim_item_del_parser.set_defaults(func=vim_action, item=item, action="delete")
1412
1413         vim_item_create_parser = subparsers.add_parser(commnad_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
1414         vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the %s. Must be a file or yaml/json text" % item).completer = FilesCompleter
1415         vim_item_create_parser.add_argument("--name", action="store", help="name of the %s" % item  )
1416         vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1417         if item=="network":
1418             vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
1419             vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
1420             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>'")
1421         else:
1422             vim_item_create_parser.add_argument("--description", action="store", help="description of the %s" % item)
1423         vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
1424
1425     argcomplete.autocomplete(main_parser)
1426     
1427     try:
1428         args = main_parser.parse_args()
1429         #logging info
1430         level = logging.CRITICAL
1431         streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
1432         if "debug" in args and args.debug:
1433             level = logging.DEBUG
1434         logging.basicConfig(format=streamformat, level= level)
1435         logger = logging.getLogger('mano')
1436         logger.setLevel(level)
1437         result = args.func(args)
1438         if result == None:
1439             result = 0
1440         #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
1441     except (requests.exceptions.ConnectionError):
1442         print "Connection error: not possible to contact OPENMANO-SERVER (openmanod)"
1443         result = -2
1444     except (KeyboardInterrupt):
1445         print 'Exiting openmano'
1446         result = -3
1447     except (SystemExit, ArgumentParserError):
1448         result = -4
1449     except OpenmanoCLIError as e:
1450         print str(e)
1451         result = -5
1452     
1453     #print result
1454     exit(result)
1455