change SDN types from tapi to ietfl2vpn, from arista to arista_cloudvision
[osm/RO.git] / RO-client / osm_roclient / roclient.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 # PYTHON_ARGCOMPLETE_OK
4
5 ##
6 # Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
7 # This file is part of openmano
8 # All Rights Reserved.
9 #
10 # Licensed under the Apache License, Version 2.0 (the "License"); you may
11 # not use this file except in compliance with the License. You may obtain
12 # a copy of the License at
13 #
14 # http://www.apache.org/licenses/LICENSE-2.0
15 #
16 # Unless required by applicable law or agreed to in writing, software
17 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
18 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
19 # License for the specific language governing permissions and limitations
20 # under the License.
21 #
22 # For those usages not covered by the Apache License, Version 2.0 please
23 # contact with: nfvlabs@tid.es
24 ##
25
26 """
27 openmano client used to interact with openmano-server (openmanod)
28 """
29 __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
30 __date__ = "$09-oct-2014 09:09:48$"
31 __version__ = "0.5.0"
32 version_date = "2019-010-04"
33
34 from argcomplete.completers import FilesCompleter
35 import os
36 import argparse
37 import argcomplete
38 import requests
39 import json
40 import yaml
41 import logging
42 #from jsonschema import validate as js_v, exceptions as js_e
43
44
45 class ArgumentParserError(Exception):
46 pass
47
48
49 class OpenmanoCLIError(Exception):
50 pass
51
52
53 class ThrowingArgumentParser(argparse.ArgumentParser):
54 def error(self, message):
55 print("Error: {}".format(message))
56 print()
57 self.print_usage()
58 #self.print_help()
59 print()
60 print("Type 'openmano -h' for help")
61 raise ArgumentParserError
62
63
64 def config(args):
65 print("OPENMANO_HOST: {}".format(mano_host))
66 print("OPENMANO_PORT: {}".format(mano_port))
67 if args.n:
68 logger.debug("resolving tenant and datacenter names")
69 mano_tenant_id = "None"
70 mano_tenant_name = "None"
71 mano_datacenter_id = "None"
72 mano_datacenter_name = "None"
73 # WIM additions
74 logger.debug("resolving WIM names")
75 mano_wim_id = "None"
76 mano_wim_name = "None"
77 try:
78 mano_tenant_id = _get_item_uuid("tenants", mano_tenant)
79 URLrequest = "http://{}:{}/openmano/tenants/{}".format(mano_host, mano_port, mano_tenant_id)
80 mano_response = requests.get(URLrequest)
81 logger.debug("openmano response: %s", mano_response.text )
82 content = mano_response.json()
83 mano_tenant_name = content["tenant"]["name"]
84 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, mano_tenant_id,
85 mano_datacenter)
86 mano_response = requests.get(URLrequest)
87 logger.debug("openmano response: %s", mano_response.text)
88 content = mano_response.json()
89 if "error" not in content:
90 mano_datacenter_id = content["datacenter"]["uuid"]
91 mano_datacenter_name = content["datacenter"]["name"]
92
93 # WIM
94 URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(
95 mano_host, mano_port, mano_tenant_id, mano_wim)
96 mano_response = requests.get(URLrequest)
97 logger.debug("openmano response: %s", mano_response.text)
98 content = mano_response.json()
99 if "error" not in content:
100 mano_wim_id = content["wim"]["uuid"]
101 mano_wim_name = content["wim"]["name"]
102
103 except OpenmanoCLIError:
104 pass
105 print( "OPENMANO_TENANT: {}".format(mano_tenant))
106 print( " Id: {}".format(mano_tenant_id))
107 print( " Name: {}".format(mano_tenant_name))
108 print( "OPENMANO_DATACENTER: {}".format(mano_datacenter))
109 print( " Id: {}".format(mano_datacenter_id))
110 print( " Name: {}".format(mano_datacenter_name))
111 # WIM
112 print( "OPENMANO_WIM: {}".format( (mano_wim)))
113 print( " Id: {}".format(mano_wim_id))
114 print( " Name: {}".format(mano_wim_name))
115
116 else:
117 print("OPENMANO_TENANT: {}".format(mano_tenant))
118 print("OPENMANO_DATACENTER: {}".format(mano_datacenter))
119 # WIM
120 print("OPENMANO_WIM: {}".format(mano_wim))
121
122 def _print_verbose(mano_response, verbose_level=0):
123 content = mano_response.json()
124 result = 0 if mano_response.status_code==200 else mano_response.status_code
125 if type(content)!=dict or len(content)!=1:
126 # print("Non expected format output")
127 print(str(content))
128 return result
129
130 val = next(iter(content.values()))
131 if type(val)==str:
132 print(val)
133 return result
134 elif type(val) == list:
135 content_list = val
136 elif type(val)==dict:
137 content_list = [val]
138 else:
139 # print("Non expected dict/list format output"
140 print(str(content))
141 return result
142
143 # print(content_list
144 if verbose_level==None:
145 verbose_level=0
146 if verbose_level >= 3:
147 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
148 return result
149
150 if mano_response.status_code == 200:
151 uuid = None
152 for content in content_list:
153 if "uuid" in content:
154 uuid = content['uuid']
155 elif "id" in content:
156 uuid = content['id']
157 elif "vim_id" in content:
158 uuid = content['vim_id']
159 name = content.get('name');
160 if not uuid:
161 uuid = ""
162 if not name:
163 name = ""
164 myoutput = "{:38} {:20}".format(uuid, name)
165 if content.get("status"):
166 myoutput += " {:20}".format(content['status'])
167 elif "enabled" in content and not content["enabled"]:
168 myoutput += " enabled=False".ljust(20)
169 if verbose_level >=1:
170 if content.get('created_at'):
171 myoutput += " {:20}".format(content['created_at'])
172 if content.get('sdn_attached_ports'):
173 #myoutput += " " + str(content['sdn_attached_ports']).ljust(20)
174 myoutput += "\nsdn_attached_ports:\n" + yaml.safe_dump(content['sdn_attached_ports'], indent=4, default_flow_style=False)
175 if verbose_level >=2:
176 new_line='\n'
177 if content.get('type'):
178 myoutput += new_line + " Type: {:29}".format(content['type'])
179 new_line=''
180 if content.get('description'):
181 myoutput += new_line + " Description: {:20}".format(content['description'])
182 print(myoutput)
183 else:
184 print(content['error']['description'])
185 return result
186
187 def parser_json_yaml(file_name):
188 try:
189 with open(file_name, "r") as f:
190 text = f.read()
191 except Exception as e:
192 return (False, str(e))
193
194 #Read and parse file
195 if file_name[-5:]=='.yaml' or file_name[-4:]=='.yml' or (file_name[-5:]!='.json' and '\t' not in text):
196 try:
197 config = yaml.load(text, Loader=yaml.SafeLoader)
198 except yaml.YAMLError as exc:
199 error_pos = ""
200 if hasattr(exc, 'problem_mark'):
201 mark = exc.problem_mark
202 error_pos = " at line:{} column:{}".format(mark.line+1, mark.column+1)
203 return (False, "Error loading file '"+file_name+"' yaml format error" + error_pos)
204 else: #json
205 try:
206 config = json.loads(text)
207 except Exception as e:
208 return (False, "Error loading file '"+file_name+"' json format error " + str(e) )
209 return True, config
210
211 def _load_file_or_yaml(content):
212 '''
213 'content' can be or a yaml/json file or a text containing a yaml/json text format
214 This function autodetect, trying to load and parse the file,
215 if fails trying to parse the 'content' text
216 Returns the dictionary once parsed, or print an error and finish the program
217 '''
218 #Check config file exists
219 if os.path.isfile(content):
220 r,payload = parser_json_yaml(content)
221 if not r:
222 print(payload)
223 exit(-1)
224 elif "{" in content or ":" in content:
225 try:
226 payload = yaml.load(content)
227 except yaml.YAMLError as exc:
228 error_pos = ""
229 if hasattr(exc, 'problem_mark'):
230 mark = exc.problem_mark
231 error_pos = " at position: ({}:{})".format(mark.line+1, mark.column+1)
232 print("Error loading yaml/json text"+error_pos)
233 exit (-1)
234 else:
235 print("'{}' is neither a valid file nor a yaml/json content".format(content))
236 exit(-1)
237 return payload
238
239 def _get_item_uuid(item, item_name_id, tenant=None):
240 if tenant:
241 URLrequest = "http://{}:{}/openmano/{}/{}".format(mano_host, mano_port, tenant, item)
242 else:
243 URLrequest = "http://{}:{}/openmano/{}".format(mano_host, mano_port, item)
244 mano_response = requests.get(URLrequest)
245 logger.debug("openmano response: %s", mano_response.text )
246 content = mano_response.json()
247 # print(content
248 found = 0
249 for i in content[item]:
250 if i["uuid"] == item_name_id:
251 return item_name_id
252 if i["name"] == item_name_id:
253 uuid = i["uuid"]
254 found += 1
255 if item_name_id.startswith("osm_id=") and i.get("osm_id") == item_name_id[7:]:
256 uuid = i["uuid"]
257 found += 1
258 if found == 0:
259 raise OpenmanoCLIError("No {} found with name/uuid '{}'".format(item[:-1], item_name_id))
260 elif found > 1:
261 raise OpenmanoCLIError("{} {} found with name '{}'. uuid must be used".format(found, item, item_name_id))
262 return uuid
263 #
264 # def check_valid_uuid(uuid):
265 # id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
266 # try:
267 # js_v(uuid, id_schema)
268 # return True
269 # except js_e.ValidationError:
270 # return False
271
272 def _get_tenant(tenant_name_id = None):
273 if not tenant_name_id:
274 tenant_name_id = mano_tenant
275 if not mano_tenant:
276 raise OpenmanoCLIError("'OPENMANO_TENANT' environment variable is not set")
277 return _get_item_uuid("tenants", tenant_name_id)
278
279 def _get_datacenter(datacenter_name_id = None, tenant = "any"):
280 if not datacenter_name_id:
281 datacenter_name_id = mano_datacenter
282 if not datacenter_name_id:
283 raise OpenmanoCLIError("neither 'OPENMANO_DATACENTER' environment variable is set nor --datacenter option is used")
284 return _get_item_uuid("datacenters", datacenter_name_id, tenant)
285
286 # WIM
287 def _get_wim(wim_name_id = None, tenant = "any"):
288 if not wim_name_id:
289 wim_name_id = mano_wim
290 if not wim_name_id:
291 raise OpenmanoCLIError("neither 'OPENMANO_WIM' environment variable is set nor --wim option is used")
292 return _get_item_uuid("wims", wim_name_id, tenant)
293
294 def vnf_create(args):
295 # print("vnf-create", args)
296 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
297 tenant = _get_tenant()
298 myvnf = _load_file_or_yaml(args.file)
299
300 api_version = ""
301 if "vnfd:vnfd-catalog" in myvnf or "vnfd-catalog" in myvnf:
302 api_version = "/v3"
303 token = "vnfd"
304 vnfd_catalog = myvnf.get("vnfd:vnfd-catalog")
305 if not vnfd_catalog:
306 vnfd_catalog = myvnf.get("vnfd-catalog")
307 vnfds = vnfd_catalog.get("vnfd:vnfd")
308 if not vnfds:
309 vnfds = vnfd_catalog.get("vnfd")
310 vnfd = vnfds[0]
311 vdu_list = vnfd.get("vdu")
312
313 else: # old API
314 api_version = ""
315 token = "vnfs"
316 vnfd = myvnf['vnf']
317 vdu_list = vnfd.get("VNFC")
318
319 if args.name or args.description or args.image_path or args.image_name or args.image_checksum:
320 # TODO, change this for API v3
321 # print(args.name
322 try:
323 if args.name:
324 vnfd['name'] = args.name
325 if args.description:
326 vnfd['description'] = args.description
327 if vdu_list:
328 if args.image_path:
329 index = 0
330 for image_path_ in args.image_path.split(","):
331 # print("image-path", image_path_)
332 if api_version == "/v3":
333 if vdu_list[index].get("image"):
334 vdu_list[index]['image'] = image_path_
335 if "image-checksum" in vdu_list[index]:
336 del vdu_list[index]["image-checksum"]
337 else: # image name in volumes
338 vdu_list[index]["volumes"][0]["image"] = image_path_
339 if "image-checksum" in vdu_list[index]["volumes"][0]:
340 del vdu_list[index]["volumes"][0]["image-checksum"]
341 else:
342 vdu_list[index]['VNFC image'] = image_path_
343 if "image name" in vdu_list[index]:
344 del vdu_list[index]["image name"]
345 if "image checksum" in vdu_list[index]:
346 del vdu_list[index]["image checksum"]
347 index += 1
348 if args.image_name: # image name precedes if both are supplied
349 index = 0
350 for image_name_ in args.image_name.split(","):
351 if api_version == "/v3":
352 if vdu_list[index].get("image"):
353 vdu_list[index]['image'] = image_name_
354 if "image-checksum" in vdu_list[index]:
355 del vdu_list[index]["image-checksum"]
356 if vdu_list[index].get("alternative-images"):
357 for a_image in vdu_list[index]["alternative-images"]:
358 a_image['image'] = image_name_
359 if "image-checksum" in a_image:
360 del a_image["image-checksum"]
361 else: # image name in volumes
362 vdu_list[index]["volumes"][0]["image"] = image_name_
363 if "image-checksum" in vdu_list[index]["volumes"][0]:
364 del vdu_list[index]["volumes"][0]["image-checksum"]
365 else:
366 vdu_list[index]['image name'] = image_name_
367 if "VNFC image" in vdu_list[index]:
368 del vdu_list[index]["VNFC image"]
369 index += 1
370 if args.image_checksum:
371 index = 0
372 for image_checksum_ in args.image_checksum.split(","):
373 if api_version == "/v3":
374 if vdu_list[index].get("image"):
375 vdu_list[index]['image-checksum'] = image_checksum_
376 if vdu_list[index].get("alternative-images"):
377 for a_image in vdu_list[index]["alternative-images"]:
378 a_image['image-checksum'] = image_checksum_
379 else: # image name in volumes
380 vdu_list[index]["volumes"][0]["image-checksum"] = image_checksum_
381 else:
382 vdu_list[index]['image checksum'] = image_checksum_
383 index += 1
384 except (KeyError, TypeError) as e:
385 if str(e) == 'vnf': error_pos= "missing field 'vnf'"
386 elif str(e) == 'name': error_pos= "missing field 'vnf':'name'"
387 elif str(e) == 'description': error_pos= "missing field 'vnf':'description'"
388 elif str(e) == 'VNFC': error_pos= "missing field 'vnf':'VNFC'"
389 elif str(e) == str(index): error_pos= "field 'vnf':'VNFC' must be an array"
390 elif str(e) == 'VNFC image': error_pos= "missing field 'vnf':'VNFC'['VNFC image']"
391 elif str(e) == 'image name': error_pos= "missing field 'vnf':'VNFC'['image name']"
392 elif str(e) == 'image checksum': error_pos= "missing field 'vnf':'VNFC'['image checksum']"
393 else: error_pos="wrong format"
394 print("Wrong VNF descriptor: " + error_pos)
395 return -1
396 payload_req = json.dumps(myvnf)
397
398 # print(payload_req
399
400 URLrequest = "http://{}:{}/openmano{}/{}/{token}".format(mano_host, mano_port, api_version, tenant, token=token)
401 logger.debug("openmano request: %s", payload_req)
402 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
403 logger.debug("openmano response: %s", mano_response.text )
404
405 return _print_verbose(mano_response, args.verbose)
406
407 def vnf_list(args):
408 # print("vnf-list",args
409 if args.all:
410 tenant = "any"
411 else:
412 tenant = _get_tenant()
413 if args.name:
414 toshow = _get_item_uuid("vnfs", args.name, tenant)
415 URLrequest = "http://{}:{}/openmano/{}/vnfs/{}".format(mano_host, mano_port, tenant, toshow)
416 else:
417 URLrequest = "http://{}:{}/openmano/{}/vnfs".format(mano_host, mano_port, tenant)
418 mano_response = requests.get(URLrequest)
419 logger.debug("openmano response: %s", mano_response.text )
420 content = mano_response.json()
421 # print(json.dumps(content, indent=4)
422 if args.verbose==None:
423 args.verbose=0
424 result = 0 if mano_response.status_code==200 else mano_response.status_code
425 if mano_response.status_code == 200:
426 if not args.name:
427 if args.verbose >= 3:
428 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
429 return result
430 if len(content['vnfs']) == 0:
431 print("No VNFs were found.")
432 return 404 # HTTP_Not_Found
433 for vnf in content['vnfs']:
434 myoutput = "{:38} {:20}".format(vnf['uuid'], vnf['name'])
435 if vnf.get('osm_id') or args.verbose >= 1:
436 myoutput += " osm_id={:20}".format(vnf.get('osm_id'))
437 if args.verbose >= 1:
438 myoutput += " {}".format(vnf['created_at'])
439 print(myoutput)
440 if args.verbose >= 2:
441 print(" Description: {}".format(vnf['description']))
442 # print(" VNF descriptor file: {}".format(vnf['path']))
443 else:
444 if args.verbose:
445 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
446 return result
447 vnf = content['vnf']
448 print("{:38} {:20} osm_id={:20} {:20}".format(vnf['uuid'], vnf['name'], vnf.get('osm_id'),
449 vnf['created_at']), end=" ")
450 print(" Description: {}".format(vnf['description']))
451 # print(" VNF descriptor file: {}".format(vnf['path']))
452 print(" VMs:")
453 for vm in vnf['VNFC']:
454 print(" {:20} osm_id={:20} {}".format(vm['name'], vm.get('osm_id'), vm['description']))
455 if len(vnf['nets']) > 0:
456 print(" Internal nets:")
457 for net in vnf['nets']:
458 print(" {:20} {}".format(net['name'], net['description']))
459 if len(vnf['external-connections']) > 0:
460 print(" External interfaces:")
461 for interface in vnf['external-connections']:
462 print(" {:20} {:20} {:20} {:14}".format(
463 interface['external_name'], interface['vm_name'],
464 interface['internal_name'],
465 interface.get('vpci') if interface.get('vpci') else ""))
466 else:
467 print(content['error']['description'])
468 if args.verbose:
469 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
470 return result
471
472 def vnf_delete(args):
473 # print("vnf-delete",args
474 if args.all:
475 tenant = "any"
476 else:
477 tenant = _get_tenant()
478 todelete = _get_item_uuid("vnfs", args.name, tenant=tenant)
479 if not args.force:
480 r = input("Delete VNF {} (y/N)? ".format(todelete))
481 if not (len(r)>0 and r[0].lower()=="y"):
482 return 0
483 URLrequest = "http://{}:{}/openmano/{}/vnfs/{}".format(mano_host, mano_port, tenant, todelete)
484 mano_response = requests.delete(URLrequest)
485 logger.debug("openmano response: %s", mano_response.text )
486 result = 0 if mano_response.status_code==200 else mano_response.status_code
487 content = mano_response.json()
488 # print(json.dumps(content, indent=4))
489 if mano_response.status_code == 200:
490 print(content['result'])
491 else:
492 print(content['error']['description'])
493 return result
494
495 def scenario_create(args):
496 # print("scenario-create",args
497 tenant = _get_tenant()
498 headers_req = {'content-type': 'application/yaml'}
499 myscenario = _load_file_or_yaml(args.file)
500 if "nsd:nsd-catalog" in myscenario or "nsd-catalog" in myscenario:
501 api_version = "/v3"
502 token = "nsd"
503 nsd_catalog = myscenario.get("nsd:nsd-catalog")
504 if not nsd_catalog:
505 nsd_catalog = myscenario.get("nsd-catalog")
506 nsds = nsd_catalog.get("nsd:nsd")
507 if not nsds:
508 nsds = nsd_catalog.get("nsd")
509 nsd = nsds[0]
510 else: # API<v3
511 api_version = ""
512 token = "scenarios"
513 if "scenario" in myscenario:
514 nsd = myscenario["scenario"]
515 else:
516 nsd = myscenario
517 # TODO modify for API v3
518 if args.name:
519 nsd['name'] = args.name
520 if args.description:
521 nsd['description'] = args.description
522 payload_req = yaml.safe_dump(myscenario, explicit_start=True, indent=4, default_flow_style=False, tags=False,
523 allow_unicode=True)
524
525 # print(payload_req
526 URLrequest = "http://{host}:{port}/openmano{api}/{tenant}/{token}".format(
527 host=mano_host, port=mano_port, api=api_version, tenant=tenant, token=token)
528 logger.debug("openmano request: %s", payload_req)
529 mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
530 logger.debug("openmano response: %s", mano_response.text )
531 return _print_verbose(mano_response, args.verbose)
532
533 def scenario_list(args):
534 # print("scenario-list",args
535 if args.all:
536 tenant = "any"
537 else:
538 tenant = _get_tenant()
539 if args.name:
540 toshow = _get_item_uuid("scenarios", args.name, tenant)
541 URLrequest = "http://{}:{}/openmano/{}/scenarios/{}".format(mano_host, mano_port, tenant, toshow)
542 else:
543 URLrequest = "http://{}:{}/openmano/{}/scenarios".format(mano_host, mano_port, tenant)
544 mano_response = requests.get(URLrequest)
545 logger.debug("openmano response: %s", mano_response.text )
546 content = mano_response.json()
547 # print(json.dumps(content, indent=4)
548 if args.verbose==None:
549 args.verbose=0
550
551 result = 0 if mano_response.status_code==200 else mano_response.status_code
552 if mano_response.status_code == 200:
553 if not args.name:
554 if args.verbose >= 3:
555 print( yaml.safe_dump(content, indent=4, default_flow_style=False))
556 return result
557 if len(content['scenarios']) == 0:
558 print( "No scenarios were found.")
559 return 404 #HTTP_Not_Found
560 for scenario in content['scenarios']:
561 myoutput = "{:38} {:20}".format(scenario['uuid'], scenario['name'])
562 if scenario.get('osm_id') or args.verbose >= 1:
563 myoutput += " osm_id={:20}".format(scenario.get('osm_id'))
564 if args.verbose >= 1:
565 myoutput += " {}".format(scenario['created_at'])
566 print(myoutput)
567 if args.verbose >=2:
568 print(" Description: {}".format(scenario['description']))
569 else:
570 if args.verbose:
571 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
572 return result
573 scenario = content['scenario']
574 print("{:38} {:20} osm_id={:20} {:20}".format(scenario['uuid'], scenario['name'], scenario.get('osm_id'),
575 scenario['created_at']), end=" ")
576 print(" Description: {}".format(scenario['description']))
577 print(" VNFs:")
578 for vnf in scenario['vnfs']:
579 print(" {:38} {:20} vnf_index={} {}".format(vnf['vnf_id'], vnf['name'], vnf.get("member_vnf_index"),
580 vnf['description']))
581 if len(scenario['nets']) > 0:
582 print(" nets:")
583 for net in scenario['nets']:
584 description = net['description']
585 if not description: # if description does not exist, description is "-". Valid for external and internal nets.
586 description = '-'
587 vim_id = ""
588 if net.get('vim_id'):
589 vim_id = " vim_id=" + net["vim_id"]
590 external = ""
591 if net["external"]:
592 external = " external"
593 print(" {:20} {:38} {:30}{}{}".format(net['name'], net['uuid'], description, vim_id, external))
594 else:
595 print(content['error']['description'])
596 if args.verbose:
597 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
598 return result
599
600 def scenario_delete(args):
601 # print("scenario-delete",args
602 if args.all:
603 tenant = "any"
604 else:
605 tenant = _get_tenant()
606 todelete = _get_item_uuid("scenarios", args.name, tenant=tenant)
607 if not args.force:
608 r = input("Delete scenario {} (y/N)? ".format(args.name))
609 if not (len(r)>0 and r[0].lower()=="y"):
610 return 0
611 URLrequest = "http://{}:{}/openmano/{}/scenarios/{}".format(mano_host, mano_port, tenant, todelete)
612 mano_response = requests.delete(URLrequest)
613 logger.debug("openmano response: %s", mano_response.text )
614 result = 0 if mano_response.status_code==200 else mano_response.status_code
615 content = mano_response.json()
616 # print(json.dumps(content, indent=4)
617 if mano_response.status_code == 200:
618 print( content['result'])
619 else:
620 print( content['error']['description'])
621 return result
622
623 def scenario_deploy(args):
624 print("This command is deprecated, use 'openmano instance-scenario-create --scenario {} --name {}' instead!!!".format(args.scenario, args.name))
625 print()
626 args.file = None
627 args.netmap_use = None
628 args.netmap_create = None
629 args.keypair = None
630 args.keypair_auto = None
631 return instance_create(args)
632
633 # # print("scenario-deploy",args
634 # headers_req = {'content-type': 'application/json'}
635 # action = {}
636 # actionCmd="start"
637 # if args.nostart:
638 # actionCmd="reserve"
639 # action[actionCmd] = {}
640 # action[actionCmd]["instance_name"] = args.name
641 # if args.datacenter != None:
642 # action[actionCmd]["datacenter"] = args.datacenter
643 # elif mano_datacenter != None:
644 # action[actionCmd]["datacenter"] = mano_datacenter
645 #
646 # if args.description:
647 # action[actionCmd]["description"] = args.description
648 # payload_req = json.dumps(action, indent=4)
649 # # print(payload_req
650 #
651 # URLrequest = "http://{}:{}/openmano/{}/scenarios/{}/action".format(mano_host, mano_port, mano_tenant, args.scenario)
652 # logger.debug("openmano request: %s", payload_req)
653 # mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
654 # logger.debug("openmano response: %s", mano_response.text )
655 # if args.verbose==None:
656 # args.verbose=0
657 #
658 # result = 0 if mano_response.status_code==200 else mano_response.status_code
659 # content = mano_response.json()
660 # # print(json.dumps(content, indent=4))
661 # if args.verbose >= 3:
662 # print(yaml.safe_dump(content, indent=4, default_flow_style=False))
663 # return result
664 #
665 # if mano_response.status_code == 200:
666 # myoutput = "{} {}".format(content['uuid'].ljust(38),content['name'].ljust(20))
667 # if args.verbose >=1:
668 # myoutput = "{} {}".format(myoutput, content['created_at'].ljust(20))
669 # if args.verbose >=2:
670 # myoutput = "{} {} {}".format(myoutput, content['description'].ljust(30))
671 # print(myoutput)
672 # print("")
673 # print("To check the status, run the following command:")
674 # print("openmano instance-scenario-list <instance_id>"
675 # else:
676 # print(content['error']['description'])
677 # return result
678
679 def scenario_verify(args):
680 # print("scenario-verify",args)
681 tenant = _get_tenant()
682 headers_req = {'content-type': 'application/json'}
683 action = {}
684 action["verify"] = {}
685 action["verify"]["instance_name"] = "scen-verify-return5"
686 payload_req = json.dumps(action, indent=4)
687 # print(payload_req)
688
689 URLrequest = "http://{}:{}/openmano/{}/scenarios/{}/action".format(mano_host, mano_port, tenant, args.scenario)
690 logger.debug("openmano request: %s", payload_req)
691 mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
692 logger.debug("openmano response: %s", mano_response.text )
693
694 result = 0 if mano_response.status_code==200 else mano_response.status_code
695 content = mano_response.json()
696 # print(json.dumps(content, indent=4))
697 if mano_response.status_code == 200:
698 print(content['result'])
699 else:
700 print(content['error']['description'])
701 return result
702
703 def instance_create(args):
704 tenant = _get_tenant()
705 headers_req = {'content-type': 'application/yaml'}
706 myInstance={"instance": {}, "schema_version": "0.1"}
707 if args.file:
708 instance_dict = _load_file_or_yaml(args.file)
709 if "instance" not in instance_dict:
710 myInstance = {"instance": instance_dict, "schema_version": "0.1"}
711 else:
712 myInstance = instance_dict
713 if args.name:
714 myInstance["instance"]['name'] = args.name
715 if args.description:
716 myInstance["instance"]['description'] = args.description
717 if args.nostart:
718 myInstance["instance"]['action'] = "reserve"
719 #datacenter
720 datacenter = myInstance["instance"].get("datacenter")
721 if args.datacenter != None:
722 datacenter = args.datacenter
723 myInstance["instance"]["datacenter"] = _get_datacenter(datacenter, tenant)
724 #scenario
725 scenario = myInstance["instance"].get("scenario")
726 if args.scenario != None:
727 scenario = args.scenario
728 if not scenario:
729 print("you must provide a scenario in the file descriptor or with --scenario")
730 return -1
731 if isinstance(scenario, str):
732 myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
733 if args.netmap_use:
734 if "networks" not in myInstance["instance"]:
735 myInstance["instance"]["networks"] = {}
736 for net in args.netmap_use:
737 net_comma_list = net.split(",")
738 for net_comma in net_comma_list:
739 net_tuple = net_comma.split("=")
740 if len(net_tuple) != 2:
741 print("error at netmap-use. Expected net-scenario=net-datacenter. ({})?".format(net_comma))
742 return
743 net_scenario = net_tuple[0].strip()
744 net_datacenter = net_tuple[1].strip()
745 if net_scenario not in myInstance["instance"]["networks"]:
746 myInstance["instance"]["networks"][net_scenario] = {}
747 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
748 myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
749 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-use"] = net_datacenter
750 if args.netmap_create:
751 if "networks" not in myInstance["instance"]:
752 myInstance["instance"]["networks"] = {}
753 for net in args.netmap_create:
754 net_comma_list = net.split(",")
755 for net_comma in net_comma_list:
756 net_tuple = net_comma.split("=")
757 if len(net_tuple) == 1:
758 net_scenario = net_tuple[0].strip()
759 net_datacenter = None
760 elif len(net_tuple) == 2:
761 net_scenario = net_tuple[0].strip()
762 net_datacenter = net_tuple[1].strip()
763 else:
764 print("error at netmap-create. Expected net-scenario=net-datacenter or net-scenario. ({})?".format(
765 net_comma))
766 return
767 if net_scenario not in myInstance["instance"]["networks"]:
768 myInstance["instance"]["networks"][net_scenario] = {}
769 if "sites" not in myInstance["instance"]["networks"][net_scenario]:
770 myInstance["instance"]["networks"][net_scenario]["sites"] = [ {} ]
771 myInstance["instance"]["networks"][net_scenario]["sites"][0]["netmap-create"] = net_datacenter
772 if args.keypair:
773 if "cloud-config" not in myInstance["instance"]:
774 myInstance["instance"]["cloud-config"] = {}
775 cloud_config = myInstance["instance"]["cloud-config"]
776 for key in args.keypair:
777 index = key.find(":")
778 if index<0:
779 if "key-pairs" not in cloud_config:
780 cloud_config["key-pairs"] = []
781 cloud_config["key-pairs"].append(key)
782 else:
783 user = key[:index]
784 key_ = key[index+1:]
785 key_list = key_.split(",")
786 if "users" not in cloud_config:
787 cloud_config["users"] = []
788 cloud_config["users"].append({"name": user, "key-pairs": key_list })
789 if args.keypair_auto:
790 try:
791 keys=[]
792 home = os.getenv("HOME")
793 user = os.getenv("USER")
794 files = os.listdir(home+'/.ssh')
795 for file in files:
796 if file[-4:] == ".pub":
797 with open(home+'/.ssh/'+file, 'r') as f:
798 keys.append(f.read())
799 if not keys:
800 print("Cannot obtain any public ssh key from '{}'. Try not using --keymap-auto".format(home+'/.ssh'))
801 return 1
802 except Exception as e:
803 print("Cannot obtain any public ssh key. Error '{}'. Try not using --keymap-auto".format(str(e)))
804 return 1
805
806 if "cloud-config" not in myInstance["instance"]:
807 myInstance["instance"]["cloud-config"] = {}
808 cloud_config = myInstance["instance"]["cloud-config"]
809 if "key-pairs" not in cloud_config:
810 cloud_config["key-pairs"] = []
811 if user:
812 if "users" not in cloud_config:
813 cloud_config["users"] = []
814 cloud_config["users"].append({"name": user, "key-pairs": keys })
815
816 payload_req = yaml.safe_dump(myInstance, explicit_start=True, indent=4, default_flow_style=False, tags=False,
817 allow_unicode=True)
818 logger.debug("openmano request: %s", payload_req)
819 URLrequest = "http://{}:{}/openmano/{}/instances".format(mano_host, mano_port, tenant)
820 mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
821 logger.debug("openmano response: %s", mano_response.text )
822 if args.verbose==None:
823 args.verbose=0
824
825 result = 0 if mano_response.status_code==200 else mano_response.status_code
826 content = mano_response.json()
827 # print(json.dumps(content, indent=4))
828 if args.verbose >= 3:
829 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
830 return result
831
832 if mano_response.status_code == 200:
833 myoutput = "{:38} {:20}".format(content['uuid'], content['name'])
834 if args.verbose >=1:
835 myoutput = "{} {:20}".format(myoutput, content['created_at'])
836 if args.verbose >=2:
837 myoutput = "{} {:30}".format(myoutput, content['description'])
838 print(myoutput)
839 else:
840 print(content['error']['description'])
841 return result
842
843 def instance_scenario_list(args):
844 # print("instance-scenario-list",args)
845 if args.all:
846 tenant = "any"
847 else:
848 tenant = _get_tenant()
849 if args.name:
850 toshow = _get_item_uuid("instances", args.name, tenant)
851 URLrequest = "http://{}:{}/openmano/{}/instances/{}".format(mano_host, mano_port, tenant, toshow)
852 else:
853 URLrequest = "http://{}:{}/openmano/{}/instances".format(mano_host, mano_port, tenant)
854 mano_response = requests.get(URLrequest)
855 logger.debug("openmano response: %s", mano_response.text )
856 content = mano_response.json()
857 # print(json.dumps(content, indent=4)
858 if args.verbose==None:
859 args.verbose=0
860
861 result = 0 if mano_response.status_code==200 else mano_response.status_code
862 if mano_response.status_code == 200:
863 if not args.name:
864 if args.verbose >= 3:
865 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
866 return result
867 if len(content['instances']) == 0:
868 print("No scenario instances were found.")
869 return result
870 for instance in content['instances']:
871 myoutput = "{:38} {:20}".format(instance['uuid'], instance['name'])
872 if args.verbose >=1:
873 myoutput = "{} {:20}".format(myoutput, instance['created_at'])
874 print(myoutput)
875 if args.verbose >=2:
876 print("Description: {}".format(instance['description']))
877 else:
878 if args.verbose:
879 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
880 return result
881 instance = content
882 print("{:38} {:20} {:20}".format(instance['uuid'],instance['name'],instance['created_at']))
883 print("Description: {}".format(instance['description']))
884 print("Template scenario id: {}".format(instance['scenario_id']))
885 print("Template scenario name: {}".format(instance['scenario_name']))
886 print("---------------------------------------")
887 print("VNF instances: {}".format(len(instance['vnfs'])))
888 for vnf in instance['vnfs']:
889 # print(" {} {} Template vnf name: {} Template vnf id: {}".format(vnf['uuid'].ljust(38), vnf['name'].ljust(20), vnf['vnf_name'].ljust(20), vnf['vnf_id'].ljust(38))
890 print(" {:38} {:20} Template vnf id: {:38}".format(vnf['uuid'], vnf['vnf_name'], vnf['vnf_id']))
891 if len(instance['nets'])>0:
892 print("---------------------------------------")
893 print("Internal nets:")
894 for net in instance['nets']:
895 if net['created']:
896 print(" {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
897 print("---------------------------------------")
898 print("External nets:")
899 for net in instance['nets']:
900 if not net['created']:
901 print(" {:38} {:12} VIM ID: {}".format(net['uuid'], net['status'], net['vim_net_id']))
902 print("---------------------------------------")
903 print("VM instances:")
904 for vnf in instance['vnfs']:
905 for vm in vnf['vms']:
906 print(" {:38} {:20} {:20} {:12} VIM ID: {}".format(vm['uuid'], vnf['vnf_name'], vm['name'],
907 vm['status'], vm['vim_vm_id']))
908 else:
909 print(content['error']['description'])
910 if args.verbose:
911 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
912 return result
913
914 def instance_scenario_status(args):
915 print("instance-scenario-status")
916 return 0
917
918 def instance_scenario_delete(args):
919 if args.all:
920 tenant = "any"
921 else:
922 tenant = _get_tenant()
923 todelete = _get_item_uuid("instances", args.name, tenant=tenant)
924 # print("instance-scenario-delete",args)
925 if not args.force:
926 r = input("Delete scenario instance {} (y/N)? ".format(args.name))
927 if not (len(r)>0 and r[0].lower()=="y"):
928 return
929 URLrequest = "http://{}:{}/openmano/{}/instances/{}".format(mano_host, mano_port, tenant, todelete)
930 mano_response = requests.delete(URLrequest)
931 logger.debug("openmano response: %s", mano_response.text )
932 result = 0 if mano_response.status_code==200 else mano_response.status_code
933 content = mano_response.json()
934 # print(json.dumps(content, indent=4))
935 if mano_response.status_code == 200:
936 print(content['result'])
937 else:
938 print(content['error']['description'])
939 return result
940
941 def get_action(args):
942 if not args.all:
943 tenant = _get_tenant()
944 else:
945 tenant = "any"
946 if not args.instance:
947 instance_id = "any"
948 else:
949 instance_id =args.instance
950 action_id = ""
951 if args.id:
952 action_id = "/" + args.id
953 URLrequest = "http://{}:{}/openmano/{}/instances/{}/action{}".format(mano_host, mano_port, tenant, instance_id,
954 action_id)
955 mano_response = requests.get(URLrequest)
956 logger.debug("openmano response: %s", mano_response.text )
957 if args.verbose == None:
958 args.verbose = 0
959 if args.id != None:
960 args.verbose += 1
961 return _print_verbose(mano_response, args.verbose)
962
963 def instance_scenario_action(args):
964 # print("instance-scenario-action", args)
965 tenant = _get_tenant()
966 toact = _get_item_uuid("instances", args.name, tenant=tenant)
967 action={}
968 action[ args.action ] = yaml.safe_load(args.param)
969 if args.vnf:
970 action["vnfs"] = args.vnf
971 if args.vm:
972 action["vms"] = args.vm
973
974 headers_req = {'content-type': 'application/json'}
975 payload_req = json.dumps(action, indent=4)
976 URLrequest = "http://{}:{}/openmano/{}/instances/{}/action".format(mano_host, mano_port, tenant, toact)
977 logger.debug("openmano request: %s", payload_req)
978 mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
979 logger.debug("openmano response: %s", mano_response.text )
980 result = 0 if mano_response.status_code==200 else mano_response.status_code
981 content = mano_response.json()
982 # print(json.dumps(content, indent=4))
983 if mano_response.status_code == 200:
984 if args.verbose:
985 print(yaml.safe_dump(content, indent=4, default_flow_style=False))
986 return result
987 if "instance_action_id" in content:
988 print("instance_action_id={}".format(content["instance_action_id"]))
989 else:
990 for uuid,c in content.items():
991 print("{:38} {:20} {:20}".format(uuid, c.get('name'), c.get('description')))
992 else:
993 print(content['error']['description'])
994 return result
995
996
997 def instance_vnf_list(args):
998 print("instance-vnf-list")
999 return 0
1000
1001 def instance_vnf_status(args):
1002 print("instance-vnf-status")
1003 return 0
1004
1005 def tenant_create(args):
1006 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1007 tenant_dict={"name": args.name}
1008 if args.description!=None:
1009 tenant_dict["description"] = args.description
1010 payload_req = json.dumps( {"tenant": tenant_dict })
1011
1012 # print(payload_req)
1013
1014 URLrequest = "http://{}:{}/openmano/tenants".format(mano_host, mano_port)
1015 logger.debug("openmano request: %s", payload_req)
1016 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1017 logger.debug("openmano response: %s", mano_response.text )
1018 return _print_verbose(mano_response, args.verbose)
1019
1020 def tenant_list(args):
1021 # print("tenant-list",args)
1022 if args.name:
1023 toshow = _get_item_uuid("tenants", args.name)
1024 URLrequest = "http://{}:{}/openmano/tenants/{}".format(mano_host, mano_port, toshow)
1025 else:
1026 URLrequest = "http://{}:{}/openmano/tenants".format(mano_host, mano_port)
1027 mano_response = requests.get(URLrequest)
1028 logger.debug("openmano response: %s", mano_response.text )
1029 if args.verbose==None:
1030 args.verbose=0
1031 if args.name!=None:
1032 args.verbose += 1
1033 return _print_verbose(mano_response, args.verbose)
1034
1035 def tenant_delete(args):
1036 # print("tenant-delete",args)
1037 todelete = _get_item_uuid("tenants", args.name)
1038 if not args.force:
1039 r = input("Delete tenant {} (y/N)? ".format(args.name))
1040 if not (len(r)>0 and r[0].lower()=="y"):
1041 return 0
1042 URLrequest = "http://{}:{}/openmano/tenants/{}".format(mano_host, mano_port, todelete)
1043 mano_response = requests.delete(URLrequest)
1044 logger.debug("openmano response: %s", mano_response.text )
1045 result = 0 if mano_response.status_code==200 else mano_response.status_code
1046 content = mano_response.json()
1047 # print(json.dumps(content, indent=4))
1048 if mano_response.status_code == 200:
1049 print(content['result'])
1050 else:
1051 print(content['error']['description'])
1052 return result
1053
1054 def datacenter_attach(args):
1055 tenant = _get_tenant()
1056 datacenter = _get_datacenter(args.name)
1057 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1058
1059 datacenter_dict={}
1060 if args.vim_tenant_id != None:
1061 datacenter_dict['vim_tenant'] = args.vim_tenant_id
1062 if args.vim_tenant_name != None:
1063 datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
1064 if args.user != None:
1065 datacenter_dict['vim_username'] = args.user
1066 if args.password != None:
1067 datacenter_dict['vim_password'] = args.password
1068 if args.config!=None:
1069 datacenter_dict["config"] = _load_file_or_yaml(args.config)
1070
1071 payload_req = json.dumps( {"datacenter": datacenter_dict })
1072
1073 # print(payload_req)
1074
1075 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, tenant, datacenter)
1076 logger.debug("openmano request: %s", payload_req)
1077 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1078 logger.debug("openmano response: %s", mano_response.text )
1079 result = _print_verbose(mano_response, args.verbose)
1080 #provide addional information if error
1081 if mano_response.status_code != 200:
1082 content = mano_response.json()
1083 if "already in use for 'name'" in content['error']['description'] and \
1084 "to database vim_tenants table" in content['error']['description']:
1085 print("Try to specify a different name with --vim-tenant-name")
1086 return result
1087
1088
1089 def datacenter_edit_vim_tenant(args):
1090 tenant = _get_tenant()
1091 datacenter = _get_datacenter(args.name)
1092 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1093
1094 if not (args.vim_tenant_id or args.vim_tenant_name or args.user or args.password or args.config):
1095 raise OpenmanoCLIError("Error. At least one parameter must be updated.")
1096
1097 datacenter_dict = {}
1098 if args.vim_tenant_id != None:
1099 datacenter_dict['vim_tenant'] = args.vim_tenant_id
1100 if args.vim_tenant_name != None:
1101 datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
1102 if args.user != None:
1103 datacenter_dict['vim_username'] = args.user
1104 if args.password != None:
1105 datacenter_dict['vim_password'] = args.password
1106 if args.config != None:
1107 datacenter_dict["config"] = _load_file_or_yaml(args.config)
1108 payload_req = json.dumps({"datacenter": datacenter_dict})
1109
1110 # print(payload_req)
1111
1112 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, tenant, datacenter)
1113 logger.debug("openmano request: %s", payload_req)
1114 mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1115 logger.debug("openmano response: %s", mano_response.text)
1116 result = _print_verbose(mano_response, args.verbose)
1117
1118 return result
1119
1120 def datacenter_detach(args):
1121 if args.all:
1122 tenant = "any"
1123 else:
1124 tenant = _get_tenant()
1125 datacenter = _get_datacenter(args.name, tenant)
1126 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1127 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, tenant, datacenter)
1128 mano_response = requests.delete(URLrequest, headers=headers_req)
1129 logger.debug("openmano response: %s", mano_response.text )
1130 content = mano_response.json()
1131 # print(json.dumps(content, indent=4))
1132 result = 0 if mano_response.status_code==200 else mano_response.status_code
1133 if mano_response.status_code == 200:
1134 print(content['result'])
1135 else:
1136 print(content['error']['description'])
1137 return result
1138
1139 def datacenter_create(args):
1140 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1141 datacenter_dict={"name": args.name, "vim_url": args.url}
1142 if args.description!=None:
1143 datacenter_dict["description"] = args.description
1144 if args.type!=None:
1145 datacenter_dict["type"] = args.type
1146 if args.url!=None:
1147 datacenter_dict["vim_url_admin"] = args.url_admin
1148 if args.config!=None:
1149 datacenter_dict["config"] = _load_file_or_yaml(args.config)
1150 if args.sdn_controller!=None:
1151 tenant = _get_tenant()
1152 sdn_controller = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
1153 if not 'config' in datacenter_dict:
1154 datacenter_dict['config'] = {}
1155 datacenter_dict['config']['sdn-controller'] = sdn_controller
1156 payload_req = json.dumps( {"datacenter": datacenter_dict })
1157
1158 # print(payload_req)
1159
1160 URLrequest = "http://{}:{}/openmano/datacenters".format(mano_host, mano_port)
1161 logger.debug("openmano request: %s", payload_req)
1162 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1163 logger.debug("openmano response: %s", mano_response.text )
1164 return _print_verbose(mano_response, args.verbose)
1165
1166 def datacenter_delete(args):
1167 # print("datacenter-delete",args)
1168 todelete = _get_item_uuid("datacenters", args.name, "any")
1169 if not args.force:
1170 r = input("Delete datacenter {} (y/N)? ".format(args.name))
1171 if not (len(r)>0 and r[0].lower()=="y"):
1172 return 0
1173 URLrequest = "http://{}:{}/openmano/datacenters/{}".format(mano_host, mano_port, todelete)
1174 mano_response = requests.delete(URLrequest)
1175 logger.debug("openmano response: %s", mano_response.text )
1176 result = 0 if mano_response.status_code==200 else mano_response.status_code
1177 content = mano_response.json()
1178 # print(json.dumps(content, indent=4))
1179 if mano_response.status_code == 200:
1180 print(content['result'])
1181 else:
1182 print(content['error']['description'])
1183 return result
1184
1185
1186 def datacenter_list(args):
1187 # print("datacenter-list",args)
1188 tenant='any' if args.all else _get_tenant()
1189
1190 if args.name:
1191 toshow = _get_item_uuid("datacenters", args.name, tenant)
1192 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}".format(mano_host, mano_port, tenant, toshow)
1193 else:
1194 URLrequest = "http://{}:{}/openmano/{}/datacenters".format(mano_host, mano_port, tenant)
1195 mano_response = requests.get(URLrequest)
1196 logger.debug("openmano response: %s", mano_response.text )
1197 if args.verbose==None:
1198 args.verbose=0
1199 if args.name!=None:
1200 args.verbose += 1
1201 return _print_verbose(mano_response, args.verbose)
1202
1203
1204 def datacenter_sdn_port_mapping_set(args):
1205 tenant = _get_tenant()
1206 datacenter = _get_datacenter(args.name, tenant)
1207 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1208
1209 if not args.file:
1210 raise OpenmanoCLIError(
1211 "No yaml/json has been provided specifying the SDN port mapping")
1212 sdn_port_mapping = _load_file_or_yaml(args.file)
1213 payload_req = json.dumps({"sdn_port_mapping": sdn_port_mapping})
1214
1215 # read
1216 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
1217 mano_response = requests.get(URLrequest)
1218 logger.debug("openmano response: %s", mano_response.text)
1219 port_mapping = mano_response.json()
1220 if mano_response.status_code != 200:
1221 str(mano_response.json())
1222 raise OpenmanoCLIError("openmano client error: {}".format(port_mapping['error']['description']))
1223 if len(port_mapping["sdn_port_mapping"]["ports_mapping"]) > 0:
1224 if not args.force:
1225 r = input("Datacenter {} already contains a port mapping. Overwrite? (y/N)? ".format(datacenter))
1226 if not (len(r) > 0 and r[0].lower() == "y"):
1227 return 0
1228
1229 # clear
1230 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
1231 mano_response = requests.delete(URLrequest)
1232 logger.debug("openmano response: %s", mano_response.text)
1233 if mano_response.status_code != 200:
1234 return _print_verbose(mano_response, args.verbose)
1235
1236 # set
1237 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
1238 logger.debug("openmano request: %s", payload_req)
1239 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1240 logger.debug("openmano response: %s", mano_response.text)
1241 return _print_verbose(mano_response, args.verbose)
1242
1243
1244 def datacenter_sdn_port_mapping_list(args):
1245 tenant = _get_tenant()
1246 datacenter = _get_datacenter(args.name, tenant)
1247
1248 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
1249 mano_response = requests.get(URLrequest)
1250 logger.debug("openmano response: %s", mano_response.text)
1251
1252 return _print_verbose(mano_response, 4)
1253
1254
1255 def datacenter_sdn_port_mapping_clear(args):
1256 tenant = _get_tenant()
1257 datacenter = _get_datacenter(args.name, tenant)
1258
1259 if not args.force:
1260 r = input("Clean SDN port mapping for datacenter {} (y/N)? ".format(datacenter))
1261 if not (len(r) > 0 and r[0].lower() == "y"):
1262 return 0
1263
1264 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/sdn_mapping".format(mano_host, mano_port, tenant, datacenter)
1265 mano_response = requests.delete(URLrequest)
1266 logger.debug("openmano response: %s", mano_response.text)
1267
1268 return _print_verbose(mano_response, args.verbose)
1269
1270
1271 def sdn_controller_create(args):
1272 tenant = _get_tenant()
1273 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1274
1275 error_msg=[]
1276 if not args.ip: error_msg.append("'ip'")
1277 if not args.port: error_msg.append("'port'")
1278 if not args.dpid: error_msg.append("'dpid'")
1279 if not args.type: error_msg.append("'type'")
1280 if error_msg:
1281 raise OpenmanoCLIError("The following arguments are required: " + ",".join(error_msg))
1282
1283 controller_dict = {}
1284 controller_dict['name'] = args.name
1285 controller_dict['ip'] = args.ip
1286 controller_dict['port'] = int(args.port)
1287 controller_dict['dpid'] = args.dpid
1288 controller_dict['type'] = args.type
1289 if args.description != None:
1290 controller_dict['description'] = args.description
1291 if args.user != None:
1292 controller_dict['user'] = args.user
1293 if args.password != None:
1294 controller_dict['password'] = args.password
1295
1296 payload_req = json.dumps({"sdn_controller": controller_dict})
1297
1298 # print(payload_req)
1299
1300 URLrequest = "http://{}:{}/openmano/{}/sdn_controllers".format(mano_host, mano_port, tenant)
1301 logger.debug("openmano request: %s", payload_req)
1302 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1303 logger.debug("openmano response: %s", mano_response.text)
1304 result = _print_verbose(mano_response, args.verbose)
1305 return result
1306
1307
1308 def sdn_controller_edit(args):
1309 tenant = _get_tenant()
1310 controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
1311 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1312
1313 controller_dict = {}
1314 if args.new_name:
1315 controller_dict['name'] = args.new_name
1316 if args.ip:
1317 controller_dict['ip'] = args.ip
1318 if args.port:
1319 controller_dict['port'] = int(args.port)
1320 if args.dpid:
1321 controller_dict['dpid'] = args.dpid
1322 if args.type:
1323 controller_dict['type'] = args.type
1324 if args.description:
1325 controller_dict['description'] = args.description
1326 if args.user:
1327 controller_dict['user'] = args.user
1328 if args.password:
1329 controller_dict['password'] = args.password
1330
1331 if not controller_dict:
1332 raise OpenmanoCLIError("At least one parameter must be edited")
1333
1334 if not args.force:
1335 r = input("Update SDN controller {} (y/N)? ".format(args.name))
1336 if not (len(r) > 0 and r[0].lower() == "y"):
1337 return 0
1338
1339 payload_req = json.dumps({"sdn_controller": controller_dict})
1340 # print(payload_req)
1341
1342 URLrequest = "http://{}:{}/openmano/{}/sdn_controllers/{}".format(mano_host, mano_port, tenant, controller_uuid)
1343 logger.debug("openmano request: %s", payload_req)
1344 mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1345 logger.debug("openmano response: %s", mano_response.text)
1346 result = _print_verbose(mano_response, args.verbose)
1347 return result
1348
1349
1350 def sdn_controller_list(args):
1351 tenant = _get_tenant()
1352 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1353
1354 if args.name:
1355 toshow = _get_item_uuid("sdn_controllers", args.name, tenant)
1356 URLrequest = "http://{}:{}/openmano/{}/sdn_controllers/{}".format(mano_host, mano_port, tenant, toshow)
1357 else:
1358 URLrequest = "http://{}:{}/openmano/{}/sdn_controllers".format(mano_host, mano_port, tenant)
1359 # print(URLrequest)
1360 mano_response = requests.get(URLrequest)
1361 logger.debug("openmano response: %s", mano_response.text )
1362 if args.verbose==None:
1363 args.verbose=0
1364 if args.name!=None:
1365 args.verbose += 1
1366
1367 # json.dumps(mano_response.json(), indent=4)
1368 return _print_verbose(mano_response, args.verbose)
1369
1370
1371 def sdn_controller_delete(args):
1372 tenant = _get_tenant()
1373 controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
1374
1375 if not args.force:
1376 r = input("Delete SDN controller {} (y/N)? ".format(args.name))
1377 if not (len(r) > 0 and r[0].lower() == "y"):
1378 return 0
1379
1380 URLrequest = "http://{}:{}/openmano/{}/sdn_controllers/{}".format(mano_host, mano_port, tenant, controller_uuid)
1381 mano_response = requests.delete(URLrequest)
1382 logger.debug("openmano response: %s", mano_response.text)
1383 return _print_verbose(mano_response, args.verbose)
1384
1385 def vim_action(args):
1386 # print("datacenter-net-action",args)
1387 tenant = _get_tenant()
1388 datacenter = _get_datacenter(args.datacenter, tenant)
1389 if args.verbose==None:
1390 args.verbose=0
1391 if args.action=="list":
1392 URLrequest = "http://{}:{}/openmano/{}/vim/{}/{}s".format(mano_host, mano_port, tenant, datacenter, args.item)
1393 if args.name!=None:
1394 args.verbose += 1
1395 URLrequest += "/" + args.name
1396 mano_response = requests.get(URLrequest)
1397 logger.debug("openmano response: %s", mano_response.text )
1398 return _print_verbose(mano_response, args.verbose)
1399 elif args.action=="delete":
1400 URLrequest = "http://{}:{}/openmano/{}/vim/{}/{}s/{}".format(mano_host, mano_port, tenant, datacenter, args.item, args.name)
1401 mano_response = requests.delete(URLrequest)
1402 logger.debug("openmano response: %s", mano_response.text )
1403 result = 0 if mano_response.status_code==200 else mano_response.status_code
1404 content = mano_response.json()
1405 # print(json.dumps(content, indent=4))
1406 if mano_response.status_code == 200:
1407 print(content['result'])
1408 else:
1409 print(content['error']['description'])
1410 return result
1411 elif args.action=="create":
1412 headers_req = {'content-type': 'application/yaml'}
1413 if args.file:
1414 create_dict = _load_file_or_yaml(args.file)
1415 if args.item not in create_dict:
1416 create_dict = {args.item: create_dict}
1417 else:
1418 create_dict = {args.item:{}}
1419 if args.name:
1420 create_dict[args.item]['name'] = args.name
1421 #if args.description:
1422 # create_dict[args.item]['description'] = args.description
1423 if args.item=="network":
1424 if args.bind_net:
1425 create_dict[args.item]['bind_net'] = args.bind_net
1426 if args.type:
1427 create_dict[args.item]['type'] = args.type
1428 if args.shared:
1429 create_dict[args.item]['shared'] = args.shared
1430 if "name" not in create_dict[args.item]:
1431 print("You must provide a name in the descriptor file or with the --name option")
1432 return
1433 payload_req = yaml.safe_dump(create_dict, explicit_start=True, indent=4, default_flow_style=False, tags=False,
1434 allow_unicode=True)
1435 logger.debug("openmano request: %s", payload_req)
1436 URLrequest = "http://{}:{}/openmano/{}/vim/{}/{}s".format(mano_host, mano_port, tenant, datacenter, args.item)
1437 mano_response = requests.post(URLrequest, headers = headers_req, data=payload_req)
1438 logger.debug("openmano response: %s", mano_response.text )
1439 if args.verbose==None:
1440 args.verbose=0
1441 return _print_verbose(mano_response, args.verbose)
1442
1443
1444 def _get_items(item, item_name_id=None, datacenter=None, tenant=None):
1445 URLrequest = "http://{}:{}/openmano".format(mano_host, mano_port)
1446 if tenant:
1447 URLrequest += "/" + tenant
1448 if datacenter:
1449 URLrequest += "/vim/" + datacenter
1450 if item:
1451 URLrequest += "/" + item +"s"
1452 if item_name_id:
1453 URLrequest += "/" + item_name_id
1454 mano_response = requests.get(URLrequest)
1455 logger.debug("openmano response: %s", mano_response.text )
1456
1457 return mano_response
1458
1459
1460 def vim_net_sdn_attach(args):
1461 #Verify the network exists in the vim
1462 tenant = _get_tenant()
1463 datacenter = _get_datacenter(args.datacenter, tenant)
1464 result = _get_items('network', item_name_id=args.vim_net, datacenter=datacenter, tenant=tenant)
1465 content = yaml.load(result.content)
1466 if 'networks' in content:
1467 raise OpenmanoCLIError('More than one network in the vim named ' + args.vim_net + '. Use uuid instead')
1468 if 'error' in content:
1469 raise OpenmanoCLIError(yaml.safe_dump(content))
1470 network_uuid = content['network']['id']
1471
1472 #Make call to attach the dataplane port to the SND network associated to the vim network
1473 headers_req = {'content-type': 'application/yaml'}
1474 payload_req = {'port': args.port}
1475 if args.vlan:
1476 payload_req['vlan'] = int(args.vlan)
1477 if args.mac:
1478 payload_req['mac'] = args.mac
1479
1480 URLrequest = "http://{}:{}/openmano/{}/vim/{}/network/{}/attach".format(mano_host, mano_port, tenant, datacenter, network_uuid)
1481 logger.debug("openmano request: %s", payload_req)
1482 mano_response = requests.post(URLrequest, headers=headers_req, data=json.dumps(payload_req))
1483 logger.debug("openmano response: %s", mano_response.text)
1484 result = _print_verbose(mano_response, args.verbose)
1485 return result
1486
1487
1488 def vim_net_sdn_detach(args):
1489 if not args.all and not args.id:
1490 print("--all or --id must be used")
1491 return 1
1492
1493 # Verify the network exists in the vim
1494 tenant = _get_tenant()
1495 datacenter = _get_datacenter(args.datacenter, tenant)
1496 result = _get_items('network', item_name_id=args.vim_net, datacenter=datacenter, tenant=tenant)
1497 content = yaml.load(result.content)
1498 if 'networks' in content:
1499 raise OpenmanoCLIError('More than one network in the vim named ' + args.vim_net + '. Use uuid instead')
1500 if 'error' in content:
1501 raise OpenmanoCLIError(yaml.safe_dump(content))
1502 network_uuid = content['network']['id']
1503
1504 if not args.force:
1505 r = input("Confirm action' (y/N)? ")
1506 if len(r) == 0 or r[0].lower() != "y":
1507 return 0
1508
1509 if args.id:
1510 URLrequest = "http://{}:{}/openmano/{}/vim/{}/network/{}/detach/{}".format(
1511 mano_host, mano_port, tenant, datacenter, network_uuid, args.id)
1512 else:
1513 URLrequest = "http://{}:{}/openmano/{}/vim/{}/network/{}/detach".format(
1514 mano_host, mano_port, tenant, datacenter, network_uuid)
1515 mano_response = requests.delete(URLrequest)
1516 logger.debug("openmano response: %s", mano_response.text)
1517 result = _print_verbose(mano_response, args.verbose)
1518 return result
1519
1520
1521 def datacenter_net_action(args):
1522 if args.action == "net-update":
1523 print("This command is deprecated, use 'openmano datacenter-netmap-delete --all' and 'openmano"
1524 " datacenter-netmap-import' instead!!!")
1525 print()
1526 args.action = "netmap-delete"
1527 args.netmap = None
1528 args.all = True
1529 r = datacenter_netmap_action(args)
1530 if r == 0:
1531 args.force = True
1532 args.action = "netmap-import"
1533 r = datacenter_netmap_action(args)
1534 return r
1535
1536 if args.action == "net-edit":
1537 args.netmap = args.net
1538 args.name = None
1539 elif args.action == "net-list":
1540 args.netmap = None
1541 elif args.action == "net-delete":
1542 args.netmap = args.net
1543 args.all = False
1544
1545 args.action = "netmap" + args.action[3:]
1546 args.vim_name=None
1547 args.vim_id=None
1548 print("This command is deprecated, use 'openmano datacenter-{}' instead!!!".format(args.action))
1549 print()
1550 return datacenter_netmap_action(args)
1551
1552 def datacenter_netmap_action(args):
1553 tenant = _get_tenant()
1554 datacenter = _get_datacenter(args.datacenter, tenant)
1555 # print("datacenter_netmap_action",args)
1556 payload_req = None
1557 if args.verbose==None:
1558 args.verbose=0
1559 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1560 URLrequest = "http://{}:{}/openmano/{}/datacenters/{}/netmaps".format(mano_host, mano_port, tenant, datacenter)
1561
1562 if args.action=="netmap-list":
1563 if args.netmap:
1564 URLrequest += "/" + args.netmap
1565 args.verbose += 1
1566 mano_response = requests.get(URLrequest)
1567
1568 elif args.action=="netmap-delete":
1569 if args.netmap and args.all:
1570 print("you can not use a netmap name and the option --all at the same time")
1571 return 1
1572 if args.netmap:
1573 force_text= "Delete default netmap '{}' from datacenter '{}' (y/N)? ".format(args.netmap, datacenter)
1574 URLrequest += "/" + args.netmap
1575 elif args.all:
1576 force_text="Delete all default netmaps from datacenter '{}' (y/N)? ".format(datacenter)
1577 else:
1578 print("you must specify a netmap name or the option --all")
1579 return 1
1580 if not args.force:
1581 r = input(force_text)
1582 if len(r)>0 and r[0].lower()=="y":
1583 pass
1584 else:
1585 return 0
1586 mano_response = requests.delete(URLrequest, headers=headers_req)
1587 elif args.action=="netmap-import":
1588 if not args.force:
1589 r = input("Create all the available networks from datacenter '{}' as default netmaps (y/N)? ".format(datacenter))
1590 if len(r)>0 and r[0].lower()=="y":
1591 pass
1592 else:
1593 return 0
1594 URLrequest += "/upload"
1595 mano_response = requests.post(URLrequest, headers=headers_req)
1596 elif args.action=="netmap-edit" or args.action=="netmap-create":
1597 if args.file:
1598 payload = _load_file_or_yaml(args.file)
1599 else:
1600 payload = {}
1601 if "netmap" not in payload:
1602 payload = {"netmap": payload}
1603 if args.name:
1604 payload["netmap"]["name"] = args.name
1605 if args.vim_id:
1606 payload["netmap"]["vim_id"] = args.vim_id
1607 if args.action=="netmap-create" and args.vim_name:
1608 payload["netmap"]["vim_name"] = args.vim_name
1609 payload_req = json.dumps(payload)
1610 logger.debug("openmano request: %s", payload_req)
1611
1612 if args.action=="netmap-edit" and not args.force:
1613 if len(payload["netmap"]) == 0:
1614 print("You must supply some parameter to edit")
1615 return 1
1616 r = input("Edit default netmap '{}' from datacenter '{}' (y/N)? ".format(args.netmap, datacenter))
1617 if len(r)>0 and r[0].lower()=="y":
1618 pass
1619 else:
1620 return 0
1621 URLrequest += "/" + args.netmap
1622 mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1623 else: #netmap-create
1624 if "vim_name" not in payload["netmap"] and "vim_id" not in payload["netmap"]:
1625 print("You must supply either --vim-id or --vim-name option; or include one of them in the file"
1626 " descriptor")
1627 return 1
1628 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1629
1630 logger.debug("openmano response: %s", mano_response.text )
1631 return _print_verbose(mano_response, args.verbose)
1632
1633
1634 def element_edit(args):
1635 element = _get_item_uuid(args.element, args.name)
1636 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1637 URLrequest = "http://{}:{}/openmano/{}/{}".format(mano_host, mano_port, args.element, element)
1638 payload=_load_file_or_yaml(args.file)
1639 if args.element[:-1] not in payload:
1640 payload = {args.element[:-1]: payload }
1641 payload_req = json.dumps(payload)
1642
1643 # print(payload_req)
1644 if not args.force or (args.name==None and args.filer==None):
1645 r = input(" Edit " + args.element[:-1] + " " + args.name + " (y/N)? ")
1646 if len(r)>0 and r[0].lower()=="y":
1647 pass
1648 else:
1649 return 0
1650 logger.debug("openmano request: %s", payload_req)
1651 mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1652 logger.debug("openmano response: %s", mano_response.text )
1653 if args.verbose==None:
1654 args.verbose=0
1655 if args.name!=None:
1656 args.verbose += 1
1657 return _print_verbose(mano_response, args.verbose)
1658
1659
1660 def datacenter_edit(args):
1661 tenant = _get_tenant()
1662 element = _get_item_uuid('datacenters', args.name, tenant)
1663 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1664 URLrequest = "http://{}:{}/openmano/datacenters/{}".format(mano_host, mano_port, element)
1665
1666 has_arguments = False
1667 if args.file != None:
1668 has_arguments = True
1669 payload = _load_file_or_yaml(args.file)
1670 else:
1671 payload = {}
1672
1673 if args.sdn_controller != None:
1674 has_arguments = True
1675 if not 'config' in payload:
1676 payload['config'] = {}
1677 if not 'sdn-controller' in payload['config']:
1678 payload['config']['sdn-controller'] = {}
1679 if args.sdn_controller == 'null':
1680 payload['config']['sdn-controller'] = None
1681 else:
1682 payload['config']['sdn-controller'] = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
1683
1684 if not has_arguments:
1685 raise OpenmanoCLIError("At least one argument must be provided to modify the datacenter")
1686
1687 if 'datacenter' not in payload:
1688 payload = {'datacenter': payload}
1689 payload_req = json.dumps(payload)
1690
1691 # print(payload_req)
1692 if not args.force or (args.name == None and args.filer == None):
1693 r = input(" Edit datacenter " + args.name + " (y/N)? ")
1694 if len(r) > 0 and r[0].lower() == "y":
1695 pass
1696 else:
1697 return 0
1698 logger.debug("openmano request: %s", payload_req)
1699 mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1700 logger.debug("openmano response: %s", mano_response.text)
1701 if args.verbose == None:
1702 args.verbose = 0
1703 if args.name != None:
1704 args.verbose += 1
1705 return _print_verbose(mano_response, args.verbose)
1706
1707
1708 # WIM
1709 def wim_account_create(args):
1710 tenant = _get_tenant()
1711 wim = _get_wim(args.name)
1712 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1713
1714 wim_dict = {}
1715 if args.account_name is not None:
1716 wim_dict['name'] = args.account_name
1717 if args.user is not None:
1718 wim_dict['user'] = args.user
1719 if args.password is not None:
1720 wim_dict['password'] = args.password
1721 if args.config is not None:
1722 wim_dict["config"] = _load_file_or_yaml(args.config)
1723
1724 payload_req = json.dumps({"wim_account": wim_dict})
1725
1726 URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(mano_host, mano_port, tenant, wim)
1727 logger.debug("openmano request: %s", payload_req)
1728 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1729 logger.debug("openmano response: %s", mano_response.text)
1730 result = _print_verbose(mano_response, args.verbose)
1731 # provide addional information if error
1732 if mano_response.status_code != 200:
1733 content = mano_response.json()
1734 if "already in use for 'name'" in content['error']['description'] and \
1735 "to database wim_tenants table" in content['error']['description']:
1736 print("Try to specify a different name with --wim-tenant-name")
1737 return result
1738
1739
1740 def wim_account_delete(args):
1741 if args.all:
1742 tenant = "any"
1743 else:
1744 tenant = _get_tenant()
1745 wim = _get_wim(args.name, tenant)
1746 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1747 URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(mano_host, mano_port, tenant, wim)
1748 mano_response = requests.delete(URLrequest, headers=headers_req)
1749 logger.debug("openmano response: %s", mano_response.text)
1750 content = mano_response.json()
1751 # print(json.dumps(content, indent=4))
1752 result = 0 if mano_response.status_code == 200 else mano_response.status_code
1753 if mano_response.status_code == 200:
1754 print(content['result'])
1755 else:
1756 print(content['error']['description'])
1757 return result
1758
1759
1760 def wim_account_edit(args):
1761 tenant = _get_tenant()
1762 wim = _get_wim(args.name)
1763 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1764
1765 wim_dict = {}
1766 if not args.account_name:
1767 wim_dict['name'] = args.vim_tenant_name
1768 if not args.user:
1769 wim_dict['user'] = args.user
1770 if not args.password:
1771 wim_dict['password'] = args.password
1772 if not args.config:
1773 wim_dict["config"] = _load_file_or_yaml(args.config)
1774
1775 payload_req = json.dumps({"wim_account": wim_dict})
1776
1777 # print(payload_req)
1778
1779 URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(mano_host, mano_port, tenant, wim)
1780 logger.debug("openmano request: %s", payload_req)
1781 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1782 logger.debug("openmano response: %s", mano_response.text)
1783 result = _print_verbose(mano_response, args.verbose)
1784 # provide addional information if error
1785 if mano_response.status_code != 200:
1786 content = mano_response.json()
1787 if "already in use for 'name'" in content['error']['description'] and \
1788 "to database wim_tenants table" in content['error']['description']:
1789 print("Try to specify a different name with --wim-tenant-name")
1790 return result
1791
1792 def wim_create(args):
1793 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1794 wim_dict = {"name": args.name, "wim_url": args.url}
1795 if args.description != None:
1796 wim_dict["description"] = args.description
1797 if args.type != None:
1798 wim_dict["type"] = args.type
1799 if args.config != None:
1800 wim_dict["config"] = _load_file_or_yaml(args.config)
1801
1802 payload_req = json.dumps({"wim": wim_dict})
1803
1804 URLrequest = "http://{}:{}/openmano/wims".format(mano_host, mano_port)
1805 logger.debug("openmano request: %s", payload_req)
1806 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1807 logger.debug("openmano response: %s", mano_response.text)
1808 return _print_verbose(mano_response, args.verbose)
1809
1810
1811 def wim_edit(args):
1812 tenant = _get_tenant()
1813 element = _get_item_uuid('wims', args.name, tenant)
1814 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1815 URLrequest = "http://{}:{}/openmano/wims/{}".format(mano_host, mano_port, element)
1816
1817 has_arguments = False
1818 if args.file != None:
1819 has_arguments = True
1820 payload = _load_file_or_yaml(args.file)
1821 else:
1822 payload = {}
1823
1824 if not has_arguments:
1825 raise OpenmanoCLIError("At least one argument must be provided to modify the wim")
1826
1827 if 'wim' not in payload:
1828 payload = {'wim': payload}
1829 payload_req = json.dumps(payload)
1830
1831 # print(payload_req)
1832 if not args.force or (args.name == None and args.filer == None):
1833 r = input(" Edit wim " + args.name + " (y/N)? ")
1834 if len(r) > 0 and r[0].lower() == "y":
1835 pass
1836 else:
1837 return 0
1838 logger.debug("openmano request: %s", payload_req)
1839 mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
1840 logger.debug("openmano response: %s", mano_response.text)
1841 if args.verbose == None:
1842 args.verbose = 0
1843 if args.name != None:
1844 args.verbose += 1
1845 return _print_verbose(mano_response, args.verbose)
1846
1847
1848 def wim_delete(args):
1849 # print("wim-delete",args)
1850 todelete = _get_item_uuid("wims", args.name, "any")
1851 if not args.force:
1852 r = input("Delete wim {} (y/N)? ".format(args.name))
1853 if not (len(r) > 0 and r[0].lower() == "y"):
1854 return 0
1855 URLrequest = "http://{}:{}/openmano/wims/{}".format(mano_host, mano_port, todelete)
1856 mano_response = requests.delete(URLrequest)
1857 logger.debug("openmano response: %s", mano_response.text)
1858 result = 0 if mano_response.status_code == 200 else mano_response.status_code
1859 content = mano_response.json()
1860 # print(json.dumps(content, indent=4)
1861 if mano_response.status_code == 200:
1862 print(content['result'])
1863 else:
1864 print(content['error']['description'])
1865 return result
1866
1867
1868 def wim_list(args):
1869 # print("wim-list",args)
1870 tenant = 'any' if args.all else _get_tenant()
1871
1872 if args.name:
1873 toshow = _get_item_uuid("wims", args.name, tenant)
1874 URLrequest = "http://{}:{}/openmano/{}/wims/{}".format(mano_host, mano_port, tenant, toshow)
1875 else:
1876 URLrequest = "http://{}:{}/openmano/{}/wims".format(mano_host, mano_port, tenant)
1877 mano_response = requests.get(URLrequest)
1878 logger.debug("openmano response: %s", mano_response.text)
1879 if args.verbose == None:
1880 args.verbose = 0
1881 if args.name != None:
1882 args.verbose += 1
1883 return _print_verbose(mano_response, args.verbose)
1884
1885
1886 def wim_port_mapping_set(args):
1887 tenant = _get_tenant()
1888 wim = _get_wim(args.name, tenant)
1889 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1890
1891 if not args.file:
1892 raise OpenmanoCLIError(
1893 "No yaml/json has been provided specifying the WIM port mapping")
1894 wim_port_mapping = _load_file_or_yaml(args.file)
1895
1896 payload_req = json.dumps({"wim_port_mapping": wim_port_mapping})
1897
1898 # read
1899 URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
1900 mano_response = requests.get(URLrequest)
1901 logger.debug("openmano response: %s", mano_response.text)
1902 port_mapping = mano_response.json()
1903
1904 if mano_response.status_code != 200:
1905 str(mano_response.json())
1906 raise OpenmanoCLIError("openmano client error: {}".format(port_mapping['error']['description']))
1907 # TODO: check this if statement
1908 if len(port_mapping["wim_port_mapping"]) > 0:
1909 if not args.force:
1910 r = input("WIM {} already contains a port mapping. Overwrite? (y/N)? ".format(wim))
1911 if not (len(r) > 0 and r[0].lower() == "y"):
1912 return 0
1913
1914 # clear
1915 URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
1916 mano_response = requests.delete(URLrequest)
1917 logger.debug("openmano response: %s", mano_response.text)
1918 if mano_response.status_code != 200:
1919 return _print_verbose(mano_response, args.verbose)
1920
1921 # set
1922 URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
1923 logger.debug("openmano request: %s", payload_req)
1924 mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
1925 logger.debug("openmano response: %s", mano_response.text)
1926 return _print_verbose(mano_response, 4)
1927
1928
1929 def wim_port_mapping_list(args):
1930 tenant = _get_tenant()
1931 wim = _get_wim(args.name, tenant)
1932
1933 URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
1934 mano_response = requests.get(URLrequest)
1935 logger.debug("openmano response: %s", mano_response.text)
1936
1937 return _print_verbose(mano_response, 4)
1938
1939
1940 def wim_port_mapping_clear(args):
1941 tenant = _get_tenant()
1942 wim = _get_wim(args.name, tenant)
1943
1944 if not args.force:
1945 r = input("Clear WIM port mapping for wim {} (y/N)? ".format(wim))
1946 if not (len(r) > 0 and r[0].lower() == "y"):
1947 return 0
1948
1949 URLrequest = "http://{}:{}/openmano/{}/wims/{}/port_mapping".format(mano_host, mano_port, tenant, wim)
1950 mano_response = requests.delete(URLrequest)
1951 logger.debug("openmano response: %s", mano_response.text)
1952 content = mano_response.json()
1953 # print(json.dumps(content, indent=4))
1954 result = 0 if mano_response.status_code == 200 else mano_response.status_code
1955 if mano_response.status_code == 200:
1956 print(content['result'])
1957 else:
1958 print(content['error']['description'])
1959 return result
1960
1961
1962 def version(args):
1963 headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
1964 URLrequest = "http://{}:{}/openmano/version".format(mano_host, mano_port)
1965
1966 mano_response = requests.get(URLrequest, headers=headers_req)
1967 logger.debug("openmano response: %s", mano_response.text)
1968 print(mano_response.text)
1969
1970
1971 def main():
1972 global mano_host
1973 global mano_port
1974 global mano_tenant
1975 global logger
1976 mano_tenant = os.getenv('OPENMANO_TENANT', None)
1977 mano_host = os.getenv('OPENMANO_HOST',"localhost")
1978 mano_port = os.getenv('OPENMANO_PORT',"9090")
1979 mano_datacenter = os.getenv('OPENMANO_DATACENTER',None)
1980 # WIM env variable for default WIM
1981 mano_wim = os.getenv('OPENMANO_WIM', None)
1982
1983 main_parser = ThrowingArgumentParser(description='User program to interact with OPENMANO-SERVER (openmanod)')
1984 main_parser.add_argument('--version', action='version', help="get version of this client",
1985 version='%(prog)s client version ' + __version__ +
1986 " (Note: use '%(prog)s version' to get server version)")
1987
1988 subparsers = main_parser.add_subparsers(help='commands')
1989
1990 parent_parser = argparse.ArgumentParser(add_help=False)
1991 parent_parser.add_argument('--verbose', '-v', action='count', help="increase verbosity level. Use several times")
1992 parent_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
1993
1994 config_parser = subparsers.add_parser('config', parents=[parent_parser], help="prints configuration values")
1995 config_parser.add_argument("-n", action="store_true", help="resolves tenant and datacenter names")
1996 config_parser.set_defaults(func=config)
1997
1998 version_parser = subparsers.add_parser('version', parents=[parent_parser], help="get server version")
1999 version_parser.set_defaults(func=version)
2000
2001 vnf_create_parser = subparsers.add_parser('vnf-create', parents=[parent_parser], help="adds a vnf into the catalogue")
2002 vnf_create_parser.add_argument("file", action="store", help="location of the JSON file describing the VNF").completer = FilesCompleter
2003 vnf_create_parser.add_argument("--name", action="store", help="name of the VNF (if it exists in the VNF descriptor, it is overwritten)")
2004 vnf_create_parser.add_argument("--description", action="store", help="description of the VNF (if it exists in the VNF descriptor, it is overwritten)")
2005 vnf_create_parser.add_argument("--image-path", action="store", help="change image path locations (overwritten)")
2006 vnf_create_parser.add_argument("--image-name", action="store", help="change image name (overwritten)")
2007 vnf_create_parser.add_argument("--image-checksum", action="store", help="change image checksum (overwritten)")
2008 vnf_create_parser.set_defaults(func=vnf_create)
2009
2010 vnf_list_parser = subparsers.add_parser('vnf-list', parents=[parent_parser], help="lists information about a vnf")
2011 vnf_list_parser.add_argument("name", nargs='?', help="name of the VNF")
2012 vnf_list_parser.add_argument("-a", "--all", action="store_true", help="shows all vnfs, not only the owned or public ones")
2013 #vnf_list_parser.add_argument('--descriptor', help="prints the VNF descriptor", action="store_true")
2014 vnf_list_parser.set_defaults(func=vnf_list)
2015
2016 vnf_delete_parser = subparsers.add_parser('vnf-delete', parents=[parent_parser], help="deletes a vnf from the catalogue")
2017 vnf_delete_parser.add_argument("name", action="store", help="name or uuid of the VNF to be deleted")
2018 vnf_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
2019 vnf_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
2020 vnf_delete_parser.set_defaults(func=vnf_delete)
2021
2022 scenario_create_parser = subparsers.add_parser('scenario-create', parents=[parent_parser], help="adds a scenario into the OPENMANO DB")
2023 scenario_create_parser.add_argument("file", action="store", help="location of the YAML file describing the scenario").completer = FilesCompleter
2024 scenario_create_parser.add_argument("--name", action="store", help="name of the scenario (if it exists in the YAML scenario, it is overwritten)")
2025 scenario_create_parser.add_argument("--description", action="store", help="description of the scenario (if it exists in the YAML scenario, it is overwritten)")
2026 scenario_create_parser.set_defaults(func=scenario_create)
2027
2028 scenario_list_parser = subparsers.add_parser('scenario-list', parents=[parent_parser], help="lists information about a scenario")
2029 scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario")
2030 #scenario_list_parser.add_argument('--descriptor', help="prints the scenario descriptor", action="store_true")
2031 scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all scenarios, not only the owned or public ones")
2032 scenario_list_parser.set_defaults(func=scenario_list)
2033
2034 scenario_delete_parser = subparsers.add_parser('scenario-delete', parents=[parent_parser], help="deletes a scenario from the OPENMANO DB")
2035 scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario to be deleted")
2036 scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
2037 scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
2038 scenario_delete_parser.set_defaults(func=scenario_delete)
2039
2040 scenario_deploy_parser = subparsers.add_parser('scenario-deploy', parents=[parent_parser], help="deploys a scenario")
2041 scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be deployed")
2042 scenario_deploy_parser.add_argument("name", action="store", help="name of the instance")
2043 scenario_deploy_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
2044 scenario_deploy_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
2045 scenario_deploy_parser.add_argument("--description", action="store", help="description of the instance")
2046 scenario_deploy_parser.set_defaults(func=scenario_deploy)
2047
2048 scenario_deploy_parser = subparsers.add_parser('scenario-verify', help="verifies if a scenario can be deployed (deploys it and deletes it)")
2049 scenario_deploy_parser.add_argument("scenario", action="store", help="name or uuid of the scenario to be verified")
2050 scenario_deploy_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
2051 scenario_deploy_parser.set_defaults(func=scenario_verify)
2052
2053 instance_scenario_create_parser = subparsers.add_parser('instance-scenario-create', parents=[parent_parser], help="deploys a scenario")
2054 instance_scenario_create_parser.add_argument("file", nargs='?', help="descriptor of the instance. Must be a file or yaml/json text")
2055 instance_scenario_create_parser.add_argument("--scenario", action="store", help="name or uuid of the scenario to be deployed")
2056 instance_scenario_create_parser.add_argument("--name", action="store", help="name of the instance")
2057 instance_scenario_create_parser.add_argument("--nostart", action="store_true", help="does not start the vms, just reserve resources")
2058 instance_scenario_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter. Needed if several datacenters are available")
2059 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")
2060 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")
2061 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")
2062 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")
2063 instance_scenario_create_parser.add_argument("--description", action="store", help="description of the instance")
2064 instance_scenario_create_parser.set_defaults(func=instance_create)
2065
2066 instance_scenario_list_parser = subparsers.add_parser('instance-scenario-list', parents=[parent_parser], help="lists information about a scenario instance")
2067 instance_scenario_list_parser.add_argument("name", nargs='?', help="name of the scenario instance")
2068 instance_scenario_list_parser.add_argument("-a", "--all", action="store_true", help="shows all instance-scenarios, not only the owned")
2069 instance_scenario_list_parser.set_defaults(func=instance_scenario_list)
2070
2071 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)")
2072 instance_scenario_delete_parser.add_argument("name", action="store", help="name or uuid of the scenario instance to be deleted")
2073 instance_scenario_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
2074 instance_scenario_delete_parser.add_argument("-a", "--all", action="store_true", help="allow delete not owned or privated one")
2075 instance_scenario_delete_parser.set_defaults(func=instance_scenario_delete)
2076
2077 instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
2078 instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
2079 instance_scenario_action_parser.add_argument("action", action="store", type=str, \
2080 choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console", "add_public_key","vdu-scaling"],\
2081 help="action to send")
2082 instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console: novnc; reboot: type; vdu-scaling: '[{vdu-id: xxx, type: create|delete, count: 1}]'")
2083 instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
2084 instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
2085 instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
2086
2087 action_parser = subparsers.add_parser('action-list', parents=[parent_parser], help="get action over an instance status")
2088 action_parser.add_argument("id", nargs='?', action="store", help="action id")
2089 action_parser.add_argument("--instance", action="store", help="fitler by this instance_id")
2090 action_parser.add_argument("--all", action="store", help="Not filter by tenant")
2091 action_parser.set_defaults(func=get_action)
2092
2093 #instance_scenario_status_parser = subparsers.add_parser('instance-scenario-status', help="show the status of a scenario instance")
2094 #instance_scenario_status_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
2095 #instance_scenario_status_parser.set_defaults(func=instance_scenario_status)
2096
2097 tenant_create_parser = subparsers.add_parser('tenant-create', parents=[parent_parser], help="creates a new tenant")
2098 tenant_create_parser.add_argument("name", action="store", help="name for the tenant")
2099 tenant_create_parser.add_argument("--description", action="store", help="description of the tenant")
2100 tenant_create_parser.set_defaults(func=tenant_create)
2101
2102 tenant_delete_parser = subparsers.add_parser('tenant-delete', parents=[parent_parser], help="deletes a tenant from the catalogue")
2103 tenant_delete_parser.add_argument("name", action="store", help="name or uuid of the tenant to be deleted")
2104 tenant_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
2105 tenant_delete_parser.set_defaults(func=tenant_delete)
2106
2107 tenant_list_parser = subparsers.add_parser('tenant-list', parents=[parent_parser], help="lists information about a tenant")
2108 tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
2109 tenant_list_parser.set_defaults(func=tenant_list)
2110
2111 element_edit_parser = subparsers.add_parser('tenant-edit', parents=[parent_parser], help="edits one tenant")
2112 element_edit_parser.add_argument("name", help="name or uuid of the tenant")
2113 element_edit_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
2114 element_edit_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
2115 element_edit_parser.set_defaults(func=element_edit, element='tenants')
2116
2117 datacenter_create_parser = subparsers.add_parser('datacenter-create', parents=[parent_parser], help="creates a new datacenter")
2118 datacenter_create_parser.add_argument("name", action="store", help="name for the datacenter")
2119 datacenter_create_parser.add_argument("url", action="store", help="url for the datacenter")
2120 datacenter_create_parser.add_argument("--url_admin", action="store", help="url for administration for the datacenter")
2121 datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
2122 datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
2123 datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
2124 datacenter_create_parser.add_argument("--sdn-controller", action="store", help="Name or uuid of the SDN controller to be used", dest='sdn_controller')
2125 datacenter_create_parser.set_defaults(func=datacenter_create)
2126
2127 datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
2128 datacenter_delete_parser.add_argument("name", action="store", help="name or uuid of the datacenter to be deleted")
2129 datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
2130 datacenter_delete_parser.set_defaults(func=datacenter_delete)
2131
2132 datacenter_edit_parser = subparsers.add_parser('datacenter-edit', parents=[parent_parser], help="Edit datacenter")
2133 datacenter_edit_parser.add_argument("name", help="name or uuid of the datacenter")
2134 datacenter_edit_parser.add_argument("--file", help="json/yaml text or file with the changes").completer = FilesCompleter
2135 datacenter_edit_parser.add_argument("--sdn-controller", action="store",
2136 help="Name or uuid of the SDN controller to be used. Specify 'null' to clear entry", dest='sdn_controller')
2137 datacenter_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
2138 datacenter_edit_parser.set_defaults(func=datacenter_edit)
2139
2140 datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
2141 datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
2142 datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
2143 datacenter_list_parser.set_defaults(func=datacenter_list)
2144
2145 datacenter_attach_parser = subparsers.add_parser('datacenter-attach', parents=[parent_parser], help="associates a datacenter to the operating tenant")
2146 datacenter_attach_parser.add_argument("name", help="name or uuid of the datacenter")
2147 datacenter_attach_parser.add_argument('--vim-tenant-id', action='store', help="specify a datacenter tenant to use. A new one is created by default")
2148 datacenter_attach_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
2149 datacenter_attach_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
2150 datacenter_attach_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
2151 datacenter_attach_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
2152 datacenter_attach_parser.set_defaults(func=datacenter_attach)
2153
2154 datacenter_edit_vim_tenant_parser = subparsers.add_parser('datacenter-edit-vim-tenant', parents=[parent_parser],
2155 help="Edit the association of a datacenter to the operating tenant")
2156 datacenter_edit_vim_tenant_parser.add_argument("name", help="name or uuid of the datacenter")
2157 datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-id', action='store',
2158 help="specify a datacenter tenant to use. A new one is created by default")
2159 datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
2160 datacenter_edit_vim_tenant_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
2161 datacenter_edit_vim_tenant_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
2162 datacenter_edit_vim_tenant_parser.add_argument("--config", action="store",
2163 help="aditional configuration in json/yaml format")
2164 datacenter_edit_vim_tenant_parser.set_defaults(func=datacenter_edit_vim_tenant)
2165
2166 datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
2167 datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
2168 datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
2169 datacenter_detach_parser.set_defaults(func=datacenter_detach)
2170
2171 #=======================datacenter_sdn_port_mapping_xxx section=======================
2172 #datacenter_sdn_port_mapping_set
2173 datacenter_sdn_port_mapping_set_parser = subparsers.add_parser('datacenter-sdn-port-mapping-set',
2174 parents=[parent_parser],
2175 help="Load a file with the mapping of physical ports "
2176 "and the ports of the dataplaneswitch controlled "
2177 "by a datacenter")
2178 datacenter_sdn_port_mapping_set_parser.add_argument("name", action="store", help="specifies the datacenter")
2179 datacenter_sdn_port_mapping_set_parser.add_argument("file",
2180 help="json/yaml text or file with the port mapping").completer = FilesCompleter
2181 datacenter_sdn_port_mapping_set_parser.add_argument("-f", "--force", action="store_true",
2182 help="forces overwriting without asking")
2183 datacenter_sdn_port_mapping_set_parser.set_defaults(func=datacenter_sdn_port_mapping_set)
2184
2185 #datacenter_sdn_port_mapping_list
2186 datacenter_sdn_port_mapping_list_parser = subparsers.add_parser('datacenter-sdn-port-mapping-list',
2187 parents=[parent_parser],
2188 help="Show the SDN port mapping in a datacenter")
2189 datacenter_sdn_port_mapping_list_parser.add_argument("name", action="store", help="specifies the datacenter")
2190 datacenter_sdn_port_mapping_list_parser.set_defaults(func=datacenter_sdn_port_mapping_list)
2191
2192 # datacenter_sdn_port_mapping_clear
2193 datacenter_sdn_port_mapping_clear_parser = subparsers.add_parser('datacenter-sdn-port-mapping-clear',
2194 parents=[parent_parser],
2195 help="Clean the the SDN port mapping in a datacenter")
2196 datacenter_sdn_port_mapping_clear_parser.add_argument("name", action="store",
2197 help="specifies the datacenter")
2198 datacenter_sdn_port_mapping_clear_parser.add_argument("-f", "--force", action="store_true",
2199 help="forces clearing without asking")
2200 datacenter_sdn_port_mapping_clear_parser.set_defaults(func=datacenter_sdn_port_mapping_clear)
2201 # =======================
2202
2203 # =======================sdn_controller_xxx section=======================
2204 # sdn_controller_create
2205 sdn_controller_create_parser = subparsers.add_parser('sdn-controller-create', parents=[parent_parser],
2206 help="Creates an SDN controller entity within RO")
2207 sdn_controller_create_parser.add_argument("name", help="name of the SDN controller")
2208 sdn_controller_create_parser.add_argument("--description", action="store", help="description of the SDN controller")
2209 sdn_controller_create_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
2210 sdn_controller_create_parser.add_argument("--port", action="store", help="Port of the SDN controller")
2211 sdn_controller_create_parser.add_argument("--dpid", action="store",
2212 help="DPID of the dataplane switch controlled by this SDN controller")
2213 sdn_controller_create_parser.add_argument("--type", action="store",
2214 help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
2215 sdn_controller_create_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
2216 sdn_controller_create_parser.add_argument("--passwd", action="store", dest='password',
2217 help="password credentials for the SDN controller")
2218 sdn_controller_create_parser.set_defaults(func=sdn_controller_create)
2219
2220 # sdn_controller_edit
2221 sdn_controller_edit_parser = subparsers.add_parser('sdn-controller-edit', parents=[parent_parser],
2222 help="Update one or more options of a SDN controller")
2223 sdn_controller_edit_parser.add_argument("name", help="name or uuid of the SDN controller", )
2224 sdn_controller_edit_parser.add_argument("--name", action="store", help="Update the name of the SDN controller",
2225 dest='new_name')
2226 sdn_controller_edit_parser.add_argument("--description", action="store", help="description of the SDN controller")
2227 sdn_controller_edit_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
2228 sdn_controller_edit_parser.add_argument("--port", action="store", help="Port of the SDN controller")
2229 sdn_controller_edit_parser.add_argument("--dpid", action="store",
2230 help="DPID of the dataplane switch controlled by this SDN controller")
2231 sdn_controller_edit_parser.add_argument("--type", action="store",
2232 help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
2233 sdn_controller_edit_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
2234 sdn_controller_edit_parser.add_argument("--password", action="store",
2235 help="password credentials for the SDN controller", dest='password')
2236 sdn_controller_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
2237 #TODO: include option --file
2238 sdn_controller_edit_parser.set_defaults(func=sdn_controller_edit)
2239
2240 #sdn_controller_list
2241 sdn_controller_list_parser = subparsers.add_parser('sdn-controller-list',
2242 parents=[parent_parser],
2243 help="List the SDN controllers")
2244 sdn_controller_list_parser.add_argument("name", nargs='?', help="name or uuid of the SDN controller")
2245 sdn_controller_list_parser.set_defaults(func=sdn_controller_list)
2246
2247 # sdn_controller_delete
2248 sdn_controller_delete_parser = subparsers.add_parser('sdn-controller-delete',
2249 parents=[parent_parser],
2250 help="Delete the the SDN controller")
2251 sdn_controller_delete_parser.add_argument("name", help="name or uuid of the SDN controller")
2252 sdn_controller_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
2253 sdn_controller_delete_parser.set_defaults(func=sdn_controller_delete)
2254 # =======================
2255
2256 # WIM ======================= WIM section==================
2257
2258 # WIM create
2259 wim_create_parser = subparsers.add_parser('wim-create',
2260 parents=[parent_parser], help="creates a new wim")
2261 wim_create_parser.add_argument("name", action="store",
2262 help="name for the wim")
2263 wim_create_parser.add_argument("url", action="store",
2264 help="url for the wim")
2265 wim_create_parser.add_argument("--type", action="store",
2266 help="wim type: ietfl2vpn, dynpac, ...")
2267 wim_create_parser.add_argument("--config", action="store",
2268 help="additional configuration in json/yaml format")
2269 wim_create_parser.add_argument("--description", action="store",
2270 help="description of the wim")
2271 wim_create_parser.set_defaults(func=wim_create)
2272
2273 # WIM delete
2274 wim_delete_parser = subparsers.add_parser('wim-delete',
2275 parents=[parent_parser], help="deletes a wim from the catalogue")
2276 wim_delete_parser.add_argument("name", action="store",
2277 help="name or uuid of the wim to be deleted")
2278 wim_delete_parser.add_argument("-f", "--force", action="store_true",
2279 help="forces deletion without asking")
2280 wim_delete_parser.set_defaults(func=wim_delete)
2281
2282 # WIM edit
2283 wim_edit_parser = subparsers.add_parser('wim-edit',
2284 parents=[parent_parser], help="edits a wim")
2285 wim_edit_parser.add_argument("name", help="name or uuid of the wim")
2286 wim_edit_parser.add_argument("--file",
2287 help="json/yaml text or file with the changes")\
2288 .completer = FilesCompleter
2289 wim_edit_parser.add_argument("-f", "--force", action="store_true",
2290 help="do not prompt for confirmation")
2291 wim_edit_parser.set_defaults(func=wim_edit)
2292
2293 # WIM list
2294 wim_list_parser = subparsers.add_parser('wim-list',
2295 parents=[parent_parser],
2296 help="lists information about registered wims")
2297 wim_list_parser.add_argument("name", nargs='?',
2298 help="name or uuid of the wim")
2299 wim_list_parser.add_argument("-a", "--all", action="store_true",
2300 help="shows all wims, not only wims attached to tenant")
2301 wim_list_parser.set_defaults(func=wim_list)
2302
2303 # WIM account create
2304 wim_attach_parser = subparsers.add_parser('wim-account-create', parents=
2305 [parent_parser], help="associates a wim account to the operating tenant")
2306 wim_attach_parser.add_argument("name", help="name or uuid of the wim")
2307 wim_attach_parser.add_argument('--account-name', action='store',
2308 help="specify a name for the wim account.")
2309 wim_attach_parser.add_argument("--user", action="store",
2310 help="user credentials for the wim account")
2311 wim_attach_parser.add_argument("--password", action="store",
2312 help="password credentials for the wim account")
2313 wim_attach_parser.add_argument("--config", action="store",
2314 help="additional configuration in json/yaml format")
2315 wim_attach_parser.set_defaults(func=wim_account_create)
2316
2317 # WIM account delete
2318 wim_detach_parser = subparsers.add_parser('wim-account-delete',
2319 parents=[parent_parser],
2320 help="removes the association "
2321 "between a wim account and the operating tenant")
2322 wim_detach_parser.add_argument("name", help="name or uuid of the wim")
2323 wim_detach_parser.add_argument("-a", "--all", action="store_true",
2324 help="removes all associations from this wim")
2325 wim_detach_parser.add_argument("-f", "--force", action="store_true",
2326 help="forces delete without asking")
2327 wim_detach_parser.set_defaults(func=wim_account_delete)
2328
2329 # WIM account edit
2330 wim_attach_edit_parser = subparsers.add_parser('wim-account-edit', parents=
2331 [parent_parser], help="modifies the association of a wim account to the operating tenant")
2332 wim_attach_edit_parser.add_argument("name", help="name or uuid of the wim")
2333 wim_attach_edit_parser.add_argument('--account-name', action='store',
2334 help="specify a name for the wim account.")
2335 wim_attach_edit_parser.add_argument("--user", action="store",
2336 help="user credentials for the wim account")
2337 wim_attach_edit_parser.add_argument("--password", action="store",
2338 help="password credentials for the wim account")
2339 wim_attach_edit_parser.add_argument("--config", action="store",
2340 help="additional configuration in json/yaml format")
2341 wim_attach_edit_parser.set_defaults(func=wim_account_edit)
2342
2343 # WIM port mapping set
2344 wim_port_mapping_set_parser = subparsers.add_parser('wim-port-mapping-set',
2345 parents=[parent_parser],
2346 help="Load a file with the mappings "
2347 "of ports of a WAN switch that is "
2348 "connected to a PoP and the ports "
2349 "of the switch controlled by the PoP")
2350 wim_port_mapping_set_parser.add_argument("name", action="store",
2351 help="specifies the wim")
2352 wim_port_mapping_set_parser.add_argument("file",
2353 help="json/yaml text or file with the wim port mapping")\
2354 .completer = FilesCompleter
2355 wim_port_mapping_set_parser.add_argument("-f", "--force",
2356 action="store_true", help="forces overwriting without asking")
2357 wim_port_mapping_set_parser.set_defaults(func=wim_port_mapping_set)
2358
2359 # WIM port mapping list
2360 wim_port_mapping_list_parser = subparsers.add_parser('wim-port-mapping-list',
2361 parents=[parent_parser], help="Show the port mappings for a wim")
2362 wim_port_mapping_list_parser.add_argument("name", action="store",
2363 help="specifies the wim")
2364 wim_port_mapping_list_parser.set_defaults(func=wim_port_mapping_list)
2365
2366 # WIM port mapping clear
2367 wim_port_mapping_clear_parser = subparsers.add_parser('wim-port-mapping-clear',
2368 parents=[parent_parser], help="Clean the port mapping in a wim")
2369 wim_port_mapping_clear_parser.add_argument("name", action="store",
2370 help="specifies the wim")
2371 wim_port_mapping_clear_parser.add_argument("-f", "--force",
2372 action="store_true",
2373 help="forces clearing without asking")
2374 wim_port_mapping_clear_parser.set_defaults(func=wim_port_mapping_clear)
2375
2376 # =======================================================
2377
2378 action_dict={'net-update': 'retrieves external networks from datacenter',
2379 'net-edit': 'edits an external network',
2380 'net-delete': 'deletes an external network',
2381 'net-list': 'lists external networks from a datacenter'
2382 }
2383 for item in action_dict:
2384 datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
2385 datacenter_action_parser.add_argument("datacenter", help="name or uuid of the datacenter")
2386 if item=='net-edit' or item=='net-delete':
2387 datacenter_action_parser.add_argument("net", help="name or uuid of the datacenter net")
2388 if item=='net-edit':
2389 datacenter_action_parser.add_argument("file", help="json/yaml text or file with the changes").completer = FilesCompleter
2390 if item!='net-list':
2391 datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
2392 datacenter_action_parser.set_defaults(func=datacenter_net_action, action=item)
2393
2394
2395 action_dict={'netmap-import': 'create network senario netmap base on the datacenter networks',
2396 'netmap-create': 'create a new network senario netmap',
2397 'netmap-edit': 'edit name of a network senario netmap',
2398 'netmap-delete': 'deletes a network scenario netmap (--all for clearing all)',
2399 'netmap-list': 'list/show network scenario netmaps'
2400 }
2401 for item in action_dict:
2402 datacenter_action_parser = subparsers.add_parser('datacenter-'+item, parents=[parent_parser], help=action_dict[item])
2403 datacenter_action_parser.add_argument("--datacenter", help="name or uuid of the datacenter")
2404 #if item=='net-add':
2405 # datacenter_action_parser.add_argument("net", help="name of the network")
2406 if item=='netmap-delete':
2407 datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to delete")
2408 datacenter_action_parser.add_argument("--all", action="store_true", help="delete all netmap of this datacenter")
2409 datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
2410 if item=='netmap-edit':
2411 datacenter_action_parser.add_argument("netmap", help="name or uuid of the datacenter netmap do edit")
2412 datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file with the changes").completer = FilesCompleter
2413 datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap")
2414 datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
2415 datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
2416 if item=='netmap-list':
2417 datacenter_action_parser.add_argument("netmap", nargs='?',help="name or uuid of the datacenter netmap to show")
2418 if item=='netmap-create':
2419 datacenter_action_parser.add_argument("file", nargs='?', help="json/yaml text or file descriptor with the changes").completer = FilesCompleter
2420 datacenter_action_parser.add_argument("--name", action='store', help="name to assign to the datacenter netmap, by default same as vim-name")
2421 datacenter_action_parser.add_argument('--vim-id', action='store', help="specify vim network uuid")
2422 datacenter_action_parser.add_argument('--vim-name', action='store', help="specify vim network name")
2423 if item=='netmap-import':
2424 datacenter_action_parser.add_argument("-f","--force", action="store_true", help="do not prompt for confirmation")
2425 datacenter_action_parser.set_defaults(func=datacenter_netmap_action, action=item)
2426
2427 # =======================vim_net_sdn_xxx section=======================
2428 # vim_net_sdn_attach
2429 vim_net_sdn_attach_parser = subparsers.add_parser('vim-net-sdn-attach',
2430 parents=[parent_parser],
2431 help="Specify the port to access to an external network using SDN")
2432 vim_net_sdn_attach_parser.add_argument("vim_net", action="store",
2433 help="Name/id of the network in the vim that will be used to connect to the external network")
2434 vim_net_sdn_attach_parser.add_argument("port", action="store", help="Specifies the port in the dataplane switch to access to the external network")
2435 vim_net_sdn_attach_parser.add_argument("--vlan", action="store", help="Specifies the vlan (if any) to use in the defined port")
2436 vim_net_sdn_attach_parser.add_argument("--mac", action="store", help="Specifies the MAC (if known) of the physical device that will be reachable by this external port")
2437 vim_net_sdn_attach_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2438 vim_net_sdn_attach_parser.set_defaults(func=vim_net_sdn_attach)
2439
2440 # vim_net_sdn_detach
2441 vim_net_sdn_detach_parser = subparsers.add_parser('vim-net-sdn-detach',
2442 parents=[parent_parser],
2443 help="Remove the port information to access to an external network using SDN")
2444
2445 vim_net_sdn_detach_parser.add_argument("vim_net", action="store", help="Name/id of the vim network")
2446 vim_net_sdn_detach_parser.add_argument("--id", action="store",help="Specify the uuid of the external ports from this network to be detached")
2447 vim_net_sdn_detach_parser.add_argument("--all", action="store_true", help="Detach all external ports from this network")
2448 vim_net_sdn_detach_parser.add_argument("-f", "--force", action="store_true", help="forces clearing without asking")
2449 vim_net_sdn_detach_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2450 vim_net_sdn_detach_parser.set_defaults(func=vim_net_sdn_detach)
2451 # =======================
2452
2453 for item in ("network", "tenant", "image"):
2454 if item=="network":
2455 command_name = 'vim-net'
2456 else:
2457 command_name = 'vim-'+item
2458 vim_item_list_parser = subparsers.add_parser(command_name + '-list', parents=[parent_parser], help="list the vim " + item + "s")
2459 vim_item_list_parser.add_argument("name", nargs='?', help="name or uuid of the " + item + "s")
2460 vim_item_list_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2461 vim_item_list_parser.set_defaults(func=vim_action, item=item, action="list")
2462
2463 vim_item_del_parser = subparsers.add_parser(command_name + '-delete', parents=[parent_parser], help="list the vim " + item + "s")
2464 vim_item_del_parser.add_argument("name", help="name or uuid of the " + item + "s")
2465 vim_item_del_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2466 vim_item_del_parser.set_defaults(func=vim_action, item=item, action="delete")
2467
2468 if item == "network" or item == "tenant":
2469 vim_item_create_parser = subparsers.add_parser(command_name + '-create', parents=[parent_parser], help="create a "+item+" at vim")
2470 vim_item_create_parser.add_argument("file", nargs='?', help="descriptor of the {}. Must be a file or yaml/json text".format(item)).completer = FilesCompleter
2471 vim_item_create_parser.add_argument("--name", action="store", help="name of the {}".format(item))
2472 vim_item_create_parser.add_argument("--datacenter", action="store", help="specifies the datacenter")
2473 if item=="network":
2474 vim_item_create_parser.add_argument("--type", action="store", help="type of network, data, ptp, bridge")
2475 vim_item_create_parser.add_argument("--shared", action="store_true", help="Private or shared")
2476 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>'")
2477 else:
2478 vim_item_create_parser.add_argument("--description", action="store", help="description of the {}".format(item))
2479 vim_item_create_parser.set_defaults(func=vim_action, item=item, action="create")
2480
2481 argcomplete.autocomplete(main_parser)
2482
2483 try:
2484 args = main_parser.parse_args()
2485 #logging info
2486 level = logging.CRITICAL
2487 streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
2488 if "debug" in args and args.debug:
2489 level = logging.DEBUG
2490 logging.basicConfig(format=streamformat, level= level)
2491 logger = logging.getLogger('mano')
2492 logger.setLevel(level)
2493 # print("#TODO py3", args)
2494 result = args.func(args)
2495 if result == None:
2496 result = 0
2497 #for some reason it fails if call exit inside try instance. Need to call exit at the end !?
2498 except (requests.exceptions.ConnectionError):
2499 print("Connection error: not possible to contact OPENMANO-SERVER (openmanod)")
2500 result = -2
2501 except (KeyboardInterrupt):
2502 print('Exiting openmano')
2503 result = -3
2504 except (SystemExit, ArgumentParserError):
2505 result = -4
2506 except (AttributeError):
2507 print("Type '--help' for more information")
2508 result = -4
2509 except OpenmanoCLIError as e:
2510 # print("#TODO py3", e)
2511 print(e)
2512 result = -5
2513
2514 # print(result)
2515 exit(result)
2516
2517
2518 if __name__ == '__main__':
2519 main()
2520