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