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