blob: 7c3c5ac489ec9d72cbc5b595f883042d946d78f5 [file] [log] [blame]
tierno7edb6752016-03-21 17:37:52 +01001#!/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'''
27openmano client used to interact with openmano-server (openmanod)
28'''
29__author__="Alfonso Tierno, Gerardo Garcia"
30__date__ ="$09-oct-2014 09:09:48$"
tiernoa4e1a6e2016-08-31 14:19:40 +020031__version__="0.4.5-r489"
tierno5acf7202016-08-29 14:28:13 +020032version_date="Aug 2016"
tierno7edb6752016-03-21 17:37:52 +010033
34from argcomplete.completers import FilesCompleter
35import os
36import argparse
37import argcomplete
38import requests
39import json
40import yaml
41import logging
42#from jsonschema import validate as js_v, exceptions as js_e
43
44class ArgumentParserError(Exception): pass
45
46class OpenmanoCLIError(Exception): pass
47
48class 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
59def config(args):
60 print "OPENMANO_HOST: %s" %mano_host
61 print "OPENMANO_PORT: %s" %mano_port
garciadeblas0e9fd832016-07-08 15:20:18 +020062 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)
tierno7edb6752016-03-21 17:37:52 +010093
94def _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
150def 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
176def _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
204def _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
234def _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
241def _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
248def 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
288def 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
349def 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
372def 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
392def 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
454def 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
477def 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 return instance_create(args)
484
485# #print "scenario-deploy",args
486# headers_req = {'content-type': 'application/json'}
487# action = {}
488# actionCmd="start"
489# if args.nostart:
490# actionCmd="reserve"
491# action[actionCmd] = {}
492# action[actionCmd]["instance_name"] = args.name
493# if args.datacenter != None:
494# action[actionCmd]["datacenter"] = args.datacenter
495# elif mano_datacenter != None:
496# action[actionCmd]["datacenter"] = mano_datacenter
497#
498# if args.description:
499# action[actionCmd]["description"] = args.description
500# payload_req = json.dumps(action, indent=4)
501# #print payload_req
502#
503# URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, mano_tenant, args.scenario)
504# logger.debug("openmano request: %s", payload_req)
505# mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
506# logger.debug("openmano response: %s", mano_response.text )
507# if args.verbose==None:
508# args.verbose=0
509#
510# result = 0 if mano_response.status_code==200 else mano_response.status_code
511# content = mano_response.json()
512# #print json.dumps(content, indent=4)
513# if args.verbose >= 3:
514# print yaml.safe_dump(content, indent=4, default_flow_style=False)
515# return result
516#
517# if mano_response.status_code == 200:
518# myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
519# if args.verbose >=1:
520# myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
521# if args.verbose >=2:
522# myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
523# print myoutput
524# print ""
525# print "To check the status, run the following command:"
526# print "openmano instance-scenario-list <instance_id>"
527# else:
528# print content['error']['description']
529# return result
530
531def scenario_verify(args):
532 #print "scenario-verify",args
533 headers_req = {'content-type': 'application/json'}
534 action = {}
535 action["verify"] = {}
536 action["verify"]["instance_name"] = "scen-verify-return5"
537 payload_req = json.dumps(action, indent=4)
538 #print payload_req
539
540 URLrequest = "http://%s:%s/openmano/%s/scenarios/%s/action" %(mano_host, mano_port, mano_tenant, args.scenario)
541 logger.debug("openmano request: %s", payload_req)
542 mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
543 logger.debug("openmano response: %s", mano_response.text )
544
545 result = 0 if mano_response.status_code==200 else mano_response.status_code
546 content = mano_response.json()
547 #print json.dumps(content, indent=4)
548 if mano_response.status_code == 200:
549 print content['result']
550 else:
551 print content['error']['description']
552 return result
553
554def instance_create(args):
555 tenant = _get_tenant()
556 headers_req = {'content-type': 'application/yaml'}
557 myInstance={"instance": {}, "schema_version": "0.1"}
558 if args.file:
559 instance_dict = _load_file_or_yaml(args.file)
560 if "instance" not in instance_dict:
561 myInstance = {"instance": instance_dict, "schema_version": "0.1"}
562 else:
563 myInstance = instance_dict
564 if args.name:
565 myInstance["instance"]['name'] = args.name
566 if args.description:
567 myInstance["instance"]['description'] = args.description
568 if args.nostart:
569 myInstance["instance"]['action'] = "reserve"
570 #datacenter
571 datacenter = myInstance["instance"].get("datacenter")
572 if args.datacenter != None:
573 datacenter = args.datacenter
574 myInstance["instance"]["datacenter"] = _get_datacenter(datacenter, tenant)
575 #scenario
576 scenario = myInstance["instance"].get("scenario")
577 if args.scenario != None:
578 scenario = args.scenario
579 if not scenario:
580 print "you must provide an scenario in the file descriptor or with --scenario"
581 return -1
582 myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
583 if args.netmap_use:
584 if "networks" not in myInstance["instance"]:
585 myInstance["instance"]["networks"] = {}
586 for net in args.netmap_use:
587 net_comma_list = net.split(",")
588 for net_comma in net_comma_list:
589 net_tuple = net_comma.split("=")
590 if len(net_tuple) != 2:
591 print "error at netmap-use. Expected net-scenario=net-datacenter. (%s)?" % net_comma
592 return
593 net_scenario = net_tuple[0].strip()
594 net_datacenter = net_tuple[1].strip()
595 if net_scenario not in myInstance["instance"]["networks"]:
596 myInstance["instance"]["networks"][net_scenario] = {}
597 myInstance["instance"]["networks"][net_scenario]["netmap-use"] = net_datacenter
598 if args.netmap_create:
599 if "networks" not in myInstance["instance"]:
600 myInstance["instance"]["networks"] = {}
601 for net in args.netmap_create:
602 net_comma_list = net.split(",")
603 for net_comma in net_comma_list:
604 net_tuple = net_comma.split("=")
605 if len(net_tuple) == 1:
606 net_scenario = net_tuple[0].strip()
607 net_datacenter = None
608 elif len(net_tuple) == 2:
609 net_scenario = net_tuple[0].strip()
610 net_datacenter = net_tuple[1].strip()
611 else:
612 print "error at netmap-create. Expected net-scenario=net-datacenter or net-scenario. (%s)?" % net_comma
613 return
614 if net_scenario not in myInstance["instance"]["networks"]:
615 myInstance["instance"]["networks"][net_scenario] = {}
616 myInstance["instance"]["networks"][net_scenario]["netmap-create"] = net_datacenter
tiernoa4e1a6e2016-08-31 14:19:40 +0200617 if args.keypair:
618 if "cloud-config" not in myInstance["instance"]:
619 myInstance["instance"]["cloud-config"] = {}
620 cloud_config = myInstance["instance"]["cloud-config"]
621 for key in args.keypair:
622 index = key.find(":")
623 if index<0:
624 if "key-pairs" not in cloud_config:
625 cloud_config["key-pairs"] = []
626 cloud_config["key-pairs"].append(key)
627 else:
628 user = key[:index]
629 key_ = key[index+1:]
630 key_list = key_.split(",")
631 if "users" not in cloud_config:
632 cloud_config["users"] = []
633 cloud_config["users"].append({"name": user, "key-pairs": key_list })
634 if args.keypair_auto:
635 try:
636 keys=[]
637 home = os.getenv("HOME")
638 user = os.getenv("USER")
639 files = os.listdir(home+'/.ssh')
640 for file in files:
641 if file[-4:] == ".pub":
642 with open(home+'/.ssh/'+file, 'r') as f:
643 keys.append(f.read())
644 if not keys:
645 print "Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh')
646 return 1
647 except Exception as e:
648 print "Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e))
649 return 1
650
651 if "cloud-config" not in myInstance["instance"]:
652 myInstance["instance"]["cloud-config"] = {}
653 cloud_config = myInstance["instance"]["cloud-config"]
654 if "key-pairs" not in cloud_config:
655 cloud_config["key-pairs"] = []
656 if user:
657 if "users" not in cloud_config:
658 cloud_config["users"] = []
659 cloud_config["users"].append({"name": user, "key-pairs": keys })
tierno7edb6752016-03-21 17:37:52 +0100660
661 payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
662 logger.debug("openmano request: %s", payload_req)
663 URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
664 mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
665 logger.debug("openmano response: %s", mano_response.text )
666 if args.verbose==None:
667 args.verbose=0
668
669 result = 0 if mano_response.status_code==200 else mano_response.status_code
670 content = mano_response.json()
671 #print json.dumps(content, indent=4)
672 if args.verbose >= 3:
673 print yaml.safe_dump(content, indent=4, default_flow_style=False)
674 return result
675
676 if mano_response.status_code == 200:
677 myoutput = "%s %s" %(content['uuid'].ljust(38),content['name'].ljust(20))
678 if args.verbose >=1:
679 myoutput = "%s %s" %(myoutput, content['created_at'].ljust(20))
680 if args.verbose >=2:
681 myoutput = "%s %s %s" %(myoutput, content['description'].ljust(30))
682 print myoutput
683 else:
684 print content['error']['description']
685 return result
686
687def instance_scenario_list(args):
688 #print "instance-scenario-list",args
689 if args.all:
690 tenant = "any"
691 else:
692 tenant = _get_tenant()
693 if args.name:
694 toshow = _get_item_uuid("instances", args.name, tenant)
695 URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, toshow)
696 else:
697 URLrequest = "http://%s:%s/openmano/%s/instances" %(mano_host, mano_port, tenant)
698 mano_response = requests.get(URLrequest)
699 logger.debug("openmano response: %s", mano_response.text )
700 content = mano_response.json()
701 #print json.dumps(content, indent=4)
702 if args.verbose==None:
703 args.verbose=0
704
705 result = 0 if mano_response.status_code==200 else mano_response.status_code
706 if mano_response.status_code == 200:
707 if not args.name:
708 if args.verbose >= 3:
709 print yaml.safe_dump(content, indent=4, default_flow_style=False)
710 return result
711 if len(content['instances']) == 0:
712 print "No scenario instances were found."
713 return result
714 for instance in content['instances']:
715 myoutput = "%s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20))
716 if args.verbose >=1:
717 myoutput = "%s %s" %(myoutput, instance['created_at'].ljust(20))
718 print myoutput
719 if args.verbose >=2:
720 print "Description: %s" %instance['description']
721 else:
722 if args.verbose:
723 print yaml.safe_dump(content, indent=4, default_flow_style=False)
724 return result
725 instance = content
726 print "%s %s %s" %(instance['uuid'].ljust(38),instance['name'].ljust(20),instance['created_at'].ljust(20))
727 print "Description: %s" %instance['description']
728 print "Template scenario id: %s" %instance['scenario_id']
729 print "Template scenario name: %s" %instance['scenario_name']
730 print "---------------------------------------"
731 print "VNF instances: %d" %len(instance['vnfs'])
732 for vnf in instance['vnfs']:
733 #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))
734 print " %s %s Template vnf id: %s" %(vnf['uuid'].ljust(38), vnf['vnf_name'].ljust(20), vnf['vnf_id'].ljust(38))
735 if len(instance['nets'])>0:
736 print "---------------------------------------"
737 print "Internal nets:"
738 for net in instance['nets']:
739 if not net['external']:
740 print " %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
741 print "---------------------------------------"
742 print "External nets:"
743 for net in instance['nets']:
744 if net['external']:
745 print " %s %s VIM ID: %s" %(net['uuid'].ljust(38), net['status'].ljust(12), net['vim_net_id'])
746 print "---------------------------------------"
747 print "VM instances:"
748 for vnf in instance['vnfs']:
749 for vm in vnf['vms']:
750 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'])
751 else:
752 print content['error']['description']
753 if args.verbose:
754 print yaml.safe_dump(content, indent=4, default_flow_style=False)
755 return result
756
757def instance_scenario_status(args):
758 print "instance-scenario-status"
759 return 0
760
761def instance_scenario_delete(args):
762 if args.all:
763 tenant = "any"
764 else:
765 tenant = _get_tenant()
766 todelete = _get_item_uuid("instances", args.name, tenant=tenant)
767 #print "instance-scenario-delete",args
768 if not args.force:
769 r = raw_input("Delete scenario instance %s (y/N)? " %(args.name))
770 if not (len(r)>0 and r[0].lower()=="y"):
771 return
772 URLrequest = "http://%s:%s/openmano/%s/instances/%s" %(mano_host, mano_port, tenant, todelete)
773 mano_response = requests.delete(URLrequest)
774 logger.debug("openmano response: %s", mano_response.text )
775 result = 0 if mano_response.status_code==200 else mano_response.status_code
776 content = mano_response.json()
777 #print json.dumps(content, indent=4)
778 if mano_response.status_code == 200:
779 print content['result']
780 else:
781 print content['error']['description']
782 return result
783
784def instance_scenario_action(args):
785 #print "instance-scenario-action", args
786 tenant = _get_tenant()
787 toact = _get_item_uuid("instances", args.name, tenant=tenant)
788 action={}
789 action[ args.action ] = args.param
790 if args.vnf:
791 action["vnfs"] = args.vnf
792 if args.vm:
793 action["vms"] = args.vm
794
795 headers_req = {'content-type': 'application/json'}
796 payload_req = json.dumps(action, indent=4)
797 URLrequest = "http://%s:%s/openmano/%s/instances/%s/action" %(mano_host, mano_port, tenant, toact)
798 logger.debug("openmano request: %s", payload_req)
799 mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
800 logger.debug("openmano response: %s", mano_response.text )
801 result = 0 if mano_response.status_code==200 else mano_response.status_code
802 content = mano_response.json()
803 #print json.dumps(content, indent=4)
804 if mano_response.status_code == 200:
805 if args.verbose:
806 print yaml.safe_dump(content, indent=4, default_flow_style=False)
807 return result
808 for uuid,c in content.iteritems():
809 print "%s %s %s" %(uuid.ljust(38), c['name'].ljust(20),c['description'].ljust(20))
810 else:
811 print content['error']['description']
812 return result
813
814
815def instance_vnf_list(args):
816 print "instance-vnf-list"
817 return 0
818
819def instance_vnf_status(args):
820 print "instance-vnf-status"
821 return 0
822
823def tenant_create(args):
824 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
825 tenant_dict={"name": args.name}
826 if args.description!=None:
827 tenant_dict["description"] = args.description
828 payload_req = json.dumps( {"tenant": tenant_dict })
829
830 #print payload_req
831
832 URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
833 logger.debug("openmano request: %s", payload_req)
834 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
835 logger.debug("openmano response: %s", mano_response.text )
836 return _print_verbose(mano_response, args.verbose)
837
838def tenant_list(args):
839 #print "tenant-list",args
840 if args.name:
tierno392f2852016-05-13 12:28:55 +0200841 toshow = _get_item_uuid("tenants", args.name)
tierno7edb6752016-03-21 17:37:52 +0100842 URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, toshow)
843 else:
844 URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port)
845 mano_response = requests.get(URLrequest)
846 logger.debug("openmano response: %s", mano_response.text )
847 if args.verbose==None:
848 args.verbose=0
849 if args.name!=None:
850 args.verbose += 1
851 return _print_verbose(mano_response, args.verbose)
852
853def tenant_delete(args):
854 #print "tenant-delete",args
855 todelete = _get_item_uuid("tenants", args.name)
856 if not args.force:
857 r = raw_input("Delete tenant %s (y/N)? " %(args.name))
858 if not (len(r)>0 and r[0].lower()=="y"):
859 return 0
860 URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, todelete)
861 mano_response = requests.delete(URLrequest)
862 logger.debug("openmano response: %s", mano_response.text )
863 result = 0 if mano_response.status_code==200 else mano_response.status_code
864 content = mano_response.json()
865 #print json.dumps(content, indent=4)
866 if mano_response.status_code == 200:
867 print content['result']
868 else:
869 print content['error']['description']
870 return result
871
872def datacenter_attach(args):
873 tenant = _get_tenant()
874 datacenter = _get_datacenter(args.name)
875 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
876
877 datacenter_dict={}
878 if args.vim_tenant_id != None:
879 datacenter_dict['vim_tenant'] = args.vim_tenant_id
880 if args.vim_tenant_name != None:
881 datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
882 if args.user != None:
883 datacenter_dict['vim_username'] = args.user
884 if args.password != None:
885 datacenter_dict['vim_password'] = args.password
886 payload_req = json.dumps( {"datacenter": datacenter_dict })
887
888 #print payload_req
889
890 URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
891 logger.debug("openmano request: %s", payload_req)
892 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
893 logger.debug("openmano response: %s", mano_response.text )
894 result = _print_verbose(mano_response, args.verbose)
895 #provide addional information if error
896 if mano_response.status_code != 200:
897 content = mano_response.json()
898 if "already in use for 'name'" in content['error']['description'] and \
899 "to database vim_tenants table" in content['error']['description']:
900 print "Try to specify a different name with --vim-tenant-name"
901 return result
902
903def datacenter_detach(args):
904 if args.all:
905 tenant = "any"
906 else:
907 tenant = _get_tenant()
908 datacenter = _get_datacenter(args.name, tenant)
909 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
910 URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, datacenter)
911 mano_response = requests.delete(URLrequest, headers=headers_req)
912 logger.debug("openmano response: %s", mano_response.text )
913 content = mano_response.json()
914 #print json.dumps(content, indent=4)
915 result = 0 if mano_response.status_code==200 else mano_response.status_code
916 if mano_response.status_code == 200:
917 print content['result']
918 else:
919 print content['error']['description']
920 return result
921
922def datacenter_create(args):
923 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
924 datacenter_dict={"name": args.name, "vim_url": args.url}
925 if args.description!=None:
926 datacenter_dict["description"] = args.description
927 if args.type!=None:
928 datacenter_dict["type"] = args.type
929 if args.url!=None:
930 datacenter_dict["vim_url_admin"] = args.url_admin
931 if args.config!=None:
932 datacenter_dict["config"] = _load_file_or_yaml(args.config)
933 payload_req = json.dumps( {"datacenter": datacenter_dict })
934
935 #print payload_req
936
937 URLrequest = "http://%s:%s/openmano/datacenters" %(mano_host, mano_port)
938 logger.debug("openmano request: %s", payload_req)
939 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
940 logger.debug("openmano response: %s", mano_response.text )
941 return _print_verbose(mano_response, args.verbose)
942
943def datacenter_delete(args):
944 #print "datacenter-delete",args
945 todelete = _get_item_uuid("datacenters", args.name, "any")
946 if not args.force:
947 r = raw_input("Delete datacenter %s (y/N)? " %(args.name))
948 if not (len(r)>0 and r[0].lower()=="y"):
949 return 0
950 URLrequest = "http://%s:%s/openmano/datacenters/%s" %(mano_host, mano_port, todelete)
951 mano_response = requests.delete(URLrequest)
952 logger.debug("openmano response: %s", mano_response.text )
953 result = 0 if mano_response.status_code==200 else mano_response.status_code
954 content = mano_response.json()
955 #print json.dumps(content, indent=4)
956 if mano_response.status_code == 200:
957 print content['result']
958 else:
959 print content['error']['description']
960 return result
961
962def datacenter_list(args):
963 #print "datacenter-list",args
964 tenant='any' if args.all else _get_tenant()
965
966 if args.name:
967 toshow = _get_item_uuid("datacenters", args.name, tenant)
968 URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" %(mano_host, mano_port, tenant, toshow)
969 else:
970 URLrequest = "http://%s:%s/openmano/%s/datacenters" %(mano_host, mano_port, tenant)
971 mano_response = requests.get(URLrequest)
972 logger.debug("openmano response: %s", mano_response.text )
973 if args.verbose==None:
974 args.verbose=0
975 if args.name!=None:
976 args.verbose += 1
977 return _print_verbose(mano_response, args.verbose)
978
979def vim_action(args):
980 #print "datacenter-net-action",args
981 tenant = _get_tenant()
982 datacenter = _get_datacenter(args.datacenter, tenant)
983 if args.verbose==None:
984 args.verbose=0
985 if args.action=="list":
986 URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, tenant, datacenter, args.item)
987 if args.name!=None:
988 args.verbose += 1
989 URLrequest += "/" + args.name
990 mano_response = requests.get(URLrequest)
991 logger.debug("openmano response: %s", mano_response.text )
992 return _print_verbose(mano_response, args.verbose)
993 elif args.action=="delete":
994 URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss/%s" %(mano_host, mano_port, tenant, datacenter, args.item, args.name)
995 mano_response = requests.delete(URLrequest)
996 logger.debug("openmano response: %s", mano_response.text )
997 result = 0 if mano_response.status_code==200 else mano_response.status_code
998 content = mano_response.json()
999 #print json.dumps(content, indent=4)
1000 if mano_response.status_code == 200:
1001 print content['result']
1002 else:
1003 print content['error']['description']
1004 return result
1005 elif args.action=="create":
1006 headers_req = {'content-type': 'application/yaml'}
1007 if args.file:
1008 create_dict = _load_file_or_yaml(args.file)
1009 if args.item not in create_dict:
1010 create_dict = {args.item: create_dict}
1011 else:
1012 create_dict = {args.item:{}}
1013 if args.name:
1014 create_dict[args.item]['name'] = args.name
1015 #if args.description:
1016 # create_dict[args.item]['description'] = args.description
1017 if args.item=="vim-net":
1018 if args.bind_net:
1019 create_dict[args.item]['bind_net'] = args.bind_net
1020 if args.bind_type:
1021 create_dict[args.item]['bind_type'] = args.bind_type
1022 if args.shared:
1023 create_dict[args.item]['shared'] = args.shared
1024 if "name" not in create_dict[args.item]:
1025 print "You must provide a name in the descriptor file or with the --name option"
1026 return
1027 payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True)
1028 logger.debug("openmano request: %s", payload_req)
1029 URLrequest = "http://%s:%s/openmano/%s/vim/%s/%ss" %(mano_host, mano_port, mano_tenant, datacenter, args.item)
1030 mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
1031 logger.debug("openmano response: %s", mano_response.text )
1032 if args.verbose==None:
1033 args.verbose=0
1034 return _print_verbose(mano_response, args.verbose)
1035
1036
1037def datacenter_net_action(args):
1038 if args.action == "net-update":
tierno5acf7202016-08-29 14:28:13 +02001039 print "This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano datacenter-netmap-import' instead!!!"
tierno7edb6752016-03-21 17:37:52 +01001040 print
1041 args.action = "netmap-delete"
1042 args.netmap = None
1043 args.all = True
1044 r = datacenter_netmap_action(args)
1045 if r == 0:
1046 args.force = True
tierno5acf7202016-08-29 14:28:13 +02001047 args.action = "netmap-import"
tierno7edb6752016-03-21 17:37:52 +01001048 r = datacenter_netmap_action(args)
1049 return r
1050
1051 if args.action == "net-edit":
1052 args.netmap = args.net
1053 args.name = None
1054 elif args.action == "net-list":
1055 args.netmap = None
1056 elif args.action == "net-delete":
1057 args.netmap = args.net
1058 args.all = False
1059
1060 args.action = "netmap" + args.action[3:]
1061 args.vim_name=None
1062 args.vim_id=None
1063 print "This command is deprecated, use 'openmano datacenter-%s' instead!!!" % args.action
1064 print
1065 return datacenter_netmap_action(args)
1066
1067def datacenter_netmap_action(args):
1068 tenant = _get_tenant()
1069 datacenter = _get_datacenter(args.datacenter, tenant)
1070 #print "datacenter_netmap_action",args
1071 payload_req = None
1072 if args.verbose==None:
1073 args.verbose=0
1074 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1075 URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/netmaps" %(mano_host, mano_port, tenant, datacenter)
1076
1077 if args.action=="netmap-list":
1078 if args.netmap:
1079 URLrequest += "/" + args.netmap
1080 args.verbose += 1
1081 mano_response = requests.get(URLrequest)
1082
1083 elif args.action=="netmap-delete":
1084 if args.netmap and args.all:
1085 print "you can not use a netmap name and the option --all at the same time"
1086 return 1
1087 if args.netmap:
1088 force_text= "Delete default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter)
1089 URLrequest += "/" + args.netmap
1090 elif args.all:
1091 force_text="Delete all default netmaps from datacenter '%s' (y/N)? " % (datacenter)
1092 else:
tiernoae4a8d12016-07-08 12:30:39 +02001093 print "you must specify a netmap name or the option --all"
tierno7edb6752016-03-21 17:37:52 +01001094 return 1
1095 if not args.force:
1096 r = raw_input(force_text)
1097 if len(r)>0 and r[0].lower()=="y":
1098 pass
1099 else:
1100 return 0
1101 mano_response = requests.delete(URLrequest, headers=headers_req)
tierno5acf7202016-08-29 14:28:13 +02001102 elif args.action=="netmap-import":
tierno7edb6752016-03-21 17:37:52 +01001103 if not args.force:
1104 r = raw_input("Create all the available networks from datacenter '%s' as default netmaps (y/N)? " % (datacenter))
1105 if len(r)>0 and r[0].lower()=="y":
1106 pass
1107 else:
1108 return 0
1109 URLrequest += "/upload"
1110 mano_response = requests.post(URLrequest, headers=headers_req)
1111 elif args.action=="netmap-edit" or args.action=="netmap-create":
1112 if args.file:
1113 payload = _load_file_or_yaml(args.file)
1114 else:
1115 payload = {}
1116 if "netmap" not in payload:
1117 payload = {"netmap": payload}
1118 if args.name:
1119 payload["netmap"]["name"] = args.name
1120 if args.vim_id:
1121 payload["netmap"]["vim_id"] = args.vim_id
1122 if args.action=="netmap-create" and args.vim_name:
1123 payload["netmap"]["vim_name"] = args.vim_name
1124 payload_req = json.dumps(payload)
1125 logger.debug("openmano request: %s", payload_req)
1126
1127 if args.action=="netmap-edit" and not args.force:
1128 if len(payload["netmap"]) == 0:
1129 print "You must supply some parameter to edit"
1130 return 1
1131 r = raw_input("Edit default netmap '%s' from datacenter '%s' (y/N)? " % (args.netmap, datacenter))
1132 if len(r)>0 and r[0].lower()=="y":
1133 pass
1134 else:
1135 return 0
1136 URLrequest += "/" + args.netmap
1137 mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1138 else: #netmap-create
1139 if "vim_name" not in payload["netmap"] and "vim_id" not in payload["netmap"]:
1140 print "You must supply either --vim-id or --vim-name option; or include one of them in the file descriptor"
1141 return 1
1142 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1143
1144 logger.debug("openmano response: %s", mano_response.text )
1145 return _print_verbose(mano_response, args.verbose)
1146
1147def element_edit(args):
1148 element = _get_item_uuid(args.element, args.name)
1149 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1150 URLrequest = "http://%s:%s/openmano/%s/%s" %(mano_host, mano_port, args.element, element)
1151 payload=_load_file_or_yaml(args.file)
1152 if args.element[:-1] not in payload:
1153 payload = {args.element[:-1]: payload }
1154 payload_req = json.dumps(payload)
1155
1156 #print payload_req
1157 if not args.force or (args.name==None and args.filer==None):
1158 r = raw_input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
1159 if len(r)>0 and r[0].lower()=="y":
1160 pass
1161 else:
1162 return 0
1163 logger.debug("openmano request: %s", payload_req)
1164 mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1165 logger.debug("openmano response: %s", mano_response.text )
1166 if args.verbose==None:
1167 args.verbose=0
1168 if args.name!=None:
1169 args.verbose += 1
1170 return _print_verbose(mano_response, args.verbose)
1171
1172
1173global mano_host
1174global mano_port
1175global mano_tenant
1176
1177if __name__=="__main__":
1178
1179 mano_tenant = os.getenv('OPENMANO_TENANT', None)
1180 mano_host = os.getenv('OPENMANO_HOST',"localhost")
1181 mano_port = os.getenv('OPENMANO_PORT',"9090")
1182 mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
1183
1184 main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
1185 main_parser.add_argument('--version', action='version', version='%(prog)s ' + __version__ )
1186
1187 subparsers = main_parser.add_subparsers(help='commands')
1188
tierno7edb6752016-03-21 17:37:52 +01001189 parent_parser = argparse.ArgumentParser(add_help=False)
1190 parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
1191 parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1192
garciadeblas0e9fd832016-07-08 15:20:18 +02001193 config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
1194 config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
1195 config_parser.set_defaults(func=config)
1196
tierno7edb6752016-03-21 17:37:52 +01001197 vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
1198 vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
1199 vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1200 vnf_create_parser.add_argument("--description", action="store", help="description of the VNF (if it exists in the VNF descriptor, it is overwritten)")
1201 vnf_create_parser.add_argument("--image-path", action="store", help="change image path locations (overwritten)")
1202 vnf_create_parser.set_defaults(func=vnf_create)
1203
1204 vnf_list_parser = subparsers.add_parser('vnf-list', parents=[parent_parser], help="lists information about a vnf")
1205 vnf_list_parser.add_argument("name", nargs='?', help="name of the VNF")
1206 vnf_list_parser.add_argument("-a", "--all", action="store_true", help="shows all vnfs, not only the owned or public ones")
1207 #vnf_list_parser.add_argument('--descriptor', help="prints the VNF descriptor", action="store_true")
1208 vnf_list_parser.set_defaults(func=vnf_list)
1209
1210 vnf_delete_parser = subparsers.add_parser('vnf-delete', parents=[parent_parser], help="deletes a vnf from the catalogue")
1211 vnf_delete_parser.add_argument("name", action="store", help="name or uuid of the VNF to be deleted")
1212 vnf_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1213 vnf_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1214 vnf_delete_parser.set_defaults(func=vnf_delete)
1215
1216 scenario_create_parser = subparsers.add_parser('scenario-create', parents=[parent_parser], help="adds a scenario into the OPENMANO DB")
1217 scenario_create_parser.add_argument("file", action="store", help="location of the YAML file describing the scenario").completer = FilesCompleter
1218 scenario_create_parser.add_argument("--name", action="store", help="name of the scenario (if it exists in the YAML scenario, it is overwritten)")
1219 scenario_create_parser.add_argument("--description", action="store", help="description of the scenario (if it exists in the YAML scenario, it is overwritten)")
1220 scenario_create_parser.set_defaults(func=scenario_create)
1221
1222 scenario_list_parser = subparsers.add_parser('scenario-list', parents=[parent_parser], help="lists information about a scenario")
1223 scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario")
1224 #scenario_list_parser.add_argument('--descriptor', help="prints the scenario descriptor", action="store_true")
1225 scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all scenarios, not only the owned or public ones")
1226 scenario_list_parser.set_defaults(func=scenario_list)
1227
1228 scenario_delete_parser = subparsers.add_parser('scenario-delete', parents=[parent_parser], help="deletes a scenario from the OPENMANO DB")
1229 scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario to be deleted")
1230 scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1231 scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1232 scenario_delete_parser.set_defaults(func=scenario_delete)
1233
1234 scenario_deploy_parser = subparsers.add_parser('scenario-deploy', parents=[parent_parser], help="deploys a scenario")
1235 scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be deployed")
1236 scenario_deploy_parser.add_argument("name", action="store", help="name of the instance")
1237 scenario_deploy_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1238 scenario_deploy_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1239 scenario_deploy_parser.add_argument("--description", action="store", help="description of the instance")
1240 scenario_deploy_parser.set_defaults(func=scenario_deploy)
1241
1242 scenario_deploy_parser = subparsers.add_parser('scenario-verify', help="verifies if a scenario can be deployed (deploys it and deletes it)")
1243 scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be verified")
1244 scenario_deploy_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1245 scenario_deploy_parser.set_defaults(func=scenario_verify)
1246
1247 instance_scenario_create_parser = subparsers.add_parser('instance-scenario-create', parents=[parent_parser], help="deploys a scenario")
1248 instance_scenario_create_parser.add_argument("file", nargs='?', help="descriptor of the instance. Must be a file or yaml/json text")
1249 instance_scenario_create_parser.add_argument("--scenario", action="store", help="name or uuid of the scenario to be deployed")
1250 instance_scenario_create_parser.add_argument("--name", action="store", help="name of the instance")
1251 instance_scenario_create_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
1252 instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
1253 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")
1254 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")
tiernoa4e1a6e2016-08-31 14:19:40 +02001255 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")
1256 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")
tierno7edb6752016-03-21 17:37:52 +01001257 instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
1258 instance_scenario_create_parser.set_defaults(func=instance_create)
1259
1260 instance_scenario_list_parser = subparsers.add_parser('instance-scenario-list', parents=[parent_parser], help="lists information about a scenario instance")
1261 instance_scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario instance")
1262 instance_scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all instance-scenarios, not only the owned")
1263 instance_scenario_list_parser.set_defaults(func=instance_scenario_list)
1264
1265 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)")
1266 instance_scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario instance to be deleted")
1267 instance_scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1268 instance_scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
1269 instance_scenario_delete_parser.set_defaults(func=instance_scenario_delete)
1270
1271 instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
1272 instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1273 instance_scenario_action_parser.add_argument("action", action="store", type=str, \
1274 choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console"],\
1275 help="action to send")
1276 instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console type (novnc, ...), reboot type (TODO)")
1277 instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
1278 instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
1279 instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
1280
1281 #instance_scenario_status_parser = subparsers.add_parser('instance-scenario-status', help="show the status of a scenario instance")
1282 #instance_scenario_status_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
1283 #instance_scenario_status_parser.set_defaults(func=instance_scenario_status)
1284
1285 tenant_create_parser = subparsers.add_parser('tenant-create', parents=[parent_parser], help="creates a new tenant")
1286 tenant_create_parser.add_argument("name", action="store", help="name for the tenant")
1287 tenant_create_parser.add_argument("--description", action="store", help="description of the tenant")
1288 tenant_create_parser.set_defaults(func=tenant_create)
1289
1290 tenant_delete_parser = subparsers.add_parser('tenant-delete', parents=[parent_parser], help="deletes a tenant from the catalogue")
1291 tenant_delete_parser.add_argument("name", action="store", help="name or uuid of the tenant to be deleted")
1292 tenant_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1293 tenant_delete_parser.set_defaults(func=tenant_delete)
1294
1295 tenant_list_parser = subparsers.add_parser('tenant-list', parents=[parent_parser], help="lists information about a tenant")
1296 tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
1297 tenant_list_parser.set_defaults(func=tenant_list)
1298
1299 item_list=('tenant','datacenter') #put tenant before so that help appear in order
1300 for item in item_list:
1301 element_edit_parser = subparsers.add_parser(item+'-edit', parents=[parent_parser], help="edits one "+item)
1302 element_edit_parser.add_argument("name", help="name or uuid of the "+item)
1303 element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1304 element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1305 element_edit_parser.set_defaults(func=element_edit, element=item + 's')
1306
1307 datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
1308 datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
1309 datacenter_create_parser.add_argument("url", action="store", help="url for the datacenter")
1310 datacenter_create_parser.add_argument("--url_admin", action="store", help="url for administration for the datacenter")
1311 datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
1312 datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
1313 datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
1314 datacenter_create_parser.set_defaults(func=datacenter_create)
1315
1316 datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
1317 datacenter_delete_parser.add_argument("name", action="store", help="name or uuid of the datacenter to be deleted")
1318 datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
1319 datacenter_delete_parser.set_defaults(func=datacenter_delete)
1320
1321 datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
1322 datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
1323 datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
1324 datacenter_list_parser.set_defaults(func=datacenter_list)
1325
1326 datacenter_attach_parser = subparsers.add_parser('datacenter-attach', parents=[parent_parser], help="associates a datacenter to the operating tenant")
1327 datacenter_attach_parser.add_argument("name", help="name or uuid of the datacenter")
1328 datacenter_attach_parser.add_argument('--vim-tenant-id', action='store', help="specify a datacenter tenant to use. A new one is created by default")
1329 datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
1330 datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
1331 datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
1332 datacenter_attach_parser.set_defaults(func=datacenter_attach)
1333
1334 datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
1335 datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
1336 datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
1337 datacenter_detach_parser.set_defaults(func=datacenter_detach)
1338
1339
1340 action_dict={'net-update': 'retrieves external networks from datacenter',
1341 'net-edit': 'edits an external network',
1342 'net-delete': 'deletes an external network',
1343 'net-list': 'lists external networks from a datacenter'
1344 }
1345 for item in action_dict:
1346 datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1347 datacenter_action_parser.add_argument("datacenter", help="name or uuid of the datacenter")
1348 if item=='net-edit' or item=='net-delete':
1349 datacenter_action_parser.add_argument("net", help="name or uuid of the datacenter net")
1350 if item=='net-edit':
1351 datacenter_action_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
1352 if item!='net-list':
1353 datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1354 datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
1355
1356
tierno5acf7202016-08-29 14:28:13 +02001357 action_dict={'netmap-import': 'create network senario netmap base on the datacenter networks',
tierno7edb6752016-03-21 17:37:52 +01001358 'netmap-create': 'create a new network senario netmap',
1359 'netmap-edit': 'edit name of a network senario netmap',
1360 'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
1361 'netmap-list': 'list/show network scenario netmaps'
1362 }
1363 for item in action_dict:
1364 datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
1365 datacenter_action_parser.add_argument("--datacenter", help="name or uuid of the datacenter")
1366 #if item=='net-add':
1367 # datacenter_action_parser.add_argument("net", help="name of the network")
1368 if item=='netmap-delete':
1369 datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to delete")
1370 datacenter_action_parser.add_argument("--all", action="store_true", help="delete all netmap of this datacenter")
1371 datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1372 if item=='netmap-edit':
1373 datacenter_action_parser.add_argument("netmap", help="name or uuid of the datacenter netmap do edit")
1374 datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file with the changes").completer = FilesCompleter
1375 datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap")
1376 datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1377 datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1378 if item=='netmap-list':
1379 datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to show")
1380 if item=='netmap-create':
1381 datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file descriptor with the changes").completer = FilesCompleter
1382 datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
1383 datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
1384 datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
tierno5acf7202016-08-29 14:28:13 +02001385 if item=='netmap-import':
tierno7edb6752016-03-21 17:37:52 +01001386 datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
1387 datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)
1388
1389 for item in ("network", "tenant"):
1390 if item=="network":
1391 commnad_name = 'vim-net'
1392 else:
1393 commnad_name = 'vim-'+item
1394 vim_item_list_parser = subparsers.add_parser(commnad_name + '-list', parents=[parent_parser], help="list the vim " + item + "s")
1395 vim_item_list_parser.add_argument("name", nargs='?', help="name or uuid of the " + item + "s")
1396 vim_item_list_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1397 vim_item_list_parser.set_defaults(func=vim_action, item=item, action="list")
1398
1399 vim_item_del_parser = subparsers.add_parser(commnad_name + '-delete', parents=[parent_parser], help="list the vim " + item + "s")
1400 vim_item_del_parser.add_argument("name", help="name or uuid of the " + item + "s")
1401 vim_item_del_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1402 vim_item_del_parser.set_defaults(func=vim_action, item=item, action="delete")
1403
1404 vim_item_create_parser = subparsers.add_parser(commnad_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
1405 vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the %s. Must be a file or yaml/json text" % item).completer = FilesCompleter
1406 vim_item_create_parser.add_argument("--name", action="store", help="name of the %s" % item )
1407 vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
1408 if item=="network":
1409 vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
1410 vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
1411 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>'")
1412 else:
1413 vim_item_create_parser.add_argument("--description", action="store", help="description of the %s" % item)
1414 vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
1415
1416 argcomplete.autocomplete(main_parser)
1417
1418 try:
1419 args = main_parser.parse_args()
1420 #logging info
1421 level = logging.CRITICAL
1422 streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
1423 if "debug" in args and args.debug:
1424 level = logging.DEBUG
1425 logging.basicConfig(format=streamformat, level= level)
1426 logger = logging.getLogger('mano')
1427 logger.setLevel(level)
1428 result = args.func(args)
1429 if result == None:
1430 result = 0
1431 #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
1432 except (requests.exceptions.ConnectionError):
1433 print "Connection error: not possible to contact OPENMANO-SERVER (openmanod)"
1434 result = -2
1435 except (KeyboardInterrupt):
1436 print 'Exiting openmano'
1437 result = -3
1438 except (SystemExit, ArgumentParserError):
1439 result = -4
1440 except OpenmanoCLIError as e:
1441 print str(e)
1442 result = -5
1443
1444 #print result
1445 exit(result)
1446