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