blob: eab0e75aa0c100fcd12e4a20d5d65e69752fdde5 [file] [log] [blame]
tierno7edb6752016-03-21 17:37:52 +01001# -*- coding: utf-8 -*-
2
3##
tierno92021022018-09-12 16:29:23 +02004# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
tierno7edb6752016-03-21 17:37:52 +01005# This file is part of openmano
6# All Rights Reserved.
7#
8# Licensed under the Apache License, Version 2.0 (the "License"); you may
9# not use this file except in compliance with the License. You may obtain
10# a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17# License for the specific language governing permissions and limitations
18# under the License.
19#
20# For those usages not covered by the Apache License, Version 2.0 please
21# contact with: nfvlabs@tid.es
22##
23
sousaedu80135b92021-02-17 15:05:18 +010024"""
tierno7edb6752016-03-21 17:37:52 +010025vimconnector implements all the methods to interact with openvim using the openvim API.
sousaedu80135b92021-02-17 15:05:18 +010026"""
27__author__ = "Alfonso Tierno, Gerardo Garcia"
28__date__ = "$26-aug-2014 11:09:29$"
tierno7edb6752016-03-21 17:37:52 +010029
tierno72774862020-05-04 11:44:15 +000030from osm_ro_plugin import vimconn
tierno7edb6752016-03-21 17:37:52 +010031import requests
32import json
33import yaml
tiernoae4a8d12016-07-08 12:30:39 +020034import logging
tierno66eba6e2017-11-10 17:09:18 +010035import math
sousaedu80135b92021-02-17 15:05:18 +010036from osm_ro.openmano_schemas import (
37 id_schema,
38 name_schema,
39 nameshort_schema,
40 description_schema,
41 vlan1000_schema,
42 integer0_schema,
43)
tierno7edb6752016-03-21 17:37:52 +010044from jsonschema import validate as js_v, exceptions as js_e
tierno7d782ef2019-10-04 12:56:31 +000045from urllib.parse import quote
tierno7edb6752016-03-21 17:37:52 +010046
sousaedu80135b92021-02-17 15:05:18 +010047"""contain the openvim virtual machine status to openmano status"""
48vmStatus2manoFormat = {
49 "ACTIVE": "ACTIVE",
50 "PAUSED": "PAUSED",
51 "SUSPENDED": "SUSPENDED",
52 "INACTIVE": "INACTIVE",
53 "CREATING": "BUILD",
54 "ERROR": "ERROR",
55 "DELETED": "DELETED",
56}
57netStatus2manoFormat = {
58 "ACTIVE": "ACTIVE",
59 "INACTIVE": "INACTIVE",
60 "BUILD": "BUILD",
61 "ERROR": "ERROR",
62 "DELETED": "DELETED",
63 "DOWN": "DOWN",
64}
tierno7edb6752016-03-21 17:37:52 +010065
66
67host_schema = {
sousaedu80135b92021-02-17 15:05:18 +010068 "type": "object",
69 "properties": {
tierno7edb6752016-03-21 17:37:52 +010070 "id": id_schema,
71 "name": name_schema,
72 },
sousaedu80135b92021-02-17 15:05:18 +010073 "required": ["id"],
tierno7edb6752016-03-21 17:37:52 +010074}
75image_schema = {
sousaedu80135b92021-02-17 15:05:18 +010076 "type": "object",
77 "properties": {
tierno7edb6752016-03-21 17:37:52 +010078 "id": id_schema,
79 "name": name_schema,
80 },
sousaedu80135b92021-02-17 15:05:18 +010081 "required": ["id", "name"],
tierno7edb6752016-03-21 17:37:52 +010082}
83server_schema = {
sousaedu80135b92021-02-17 15:05:18 +010084 "type": "object",
85 "properties": {
86 "id": id_schema,
tierno7edb6752016-03-21 17:37:52 +010087 "name": name_schema,
88 },
sousaedu80135b92021-02-17 15:05:18 +010089 "required": ["id", "name"],
tierno7edb6752016-03-21 17:37:52 +010090}
91new_host_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +010092 "title": "host response information schema",
tierno7edb6752016-03-21 17:37:52 +010093 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +010094 "type": "object",
95 "properties": {"host": host_schema},
tierno7edb6752016-03-21 17:37:52 +010096 "required": ["host"],
sousaedu80135b92021-02-17 15:05:18 +010097 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +010098}
99
100get_images_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100101 "title": "openvim images response information schema",
tierno7edb6752016-03-21 17:37:52 +0100102 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100103 "type": "object",
104 "properties": {
105 "images": {
106 "type": "array",
tierno7edb6752016-03-21 17:37:52 +0100107 "items": image_schema,
108 }
109 },
110 "required": ["images"],
sousaedu80135b92021-02-17 15:05:18 +0100111 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100112}
113
114get_hosts_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100115 "title": "openvim hosts response information schema",
tierno7edb6752016-03-21 17:37:52 +0100116 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100117 "type": "object",
118 "properties": {
119 "hosts": {
120 "type": "array",
tierno7edb6752016-03-21 17:37:52 +0100121 "items": host_schema,
122 }
123 },
124 "required": ["hosts"],
sousaedu80135b92021-02-17 15:05:18 +0100125 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100126}
127
sousaedu80135b92021-02-17 15:05:18 +0100128get_host_detail_response_schema = (
129 new_host_response_schema # TODO: Content is not parsed yet
130)
tierno7edb6752016-03-21 17:37:52 +0100131
132get_server_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100133 "title": "openvim server response information schema",
tierno7edb6752016-03-21 17:37:52 +0100134 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100135 "type": "object",
136 "properties": {
137 "servers": {
138 "type": "array",
tierno7edb6752016-03-21 17:37:52 +0100139 "items": server_schema,
140 }
141 },
142 "required": ["servers"],
sousaedu80135b92021-02-17 15:05:18 +0100143 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100144}
145
146new_tenant_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100147 "title": "tenant response information schema",
tierno7edb6752016-03-21 17:37:52 +0100148 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100149 "type": "object",
150 "properties": {
151 "tenant": {
152 "type": "object",
153 "properties": {
tierno7edb6752016-03-21 17:37:52 +0100154 "id": id_schema,
155 "name": nameshort_schema,
sousaedu80135b92021-02-17 15:05:18 +0100156 "description": description_schema,
157 "enabled": {"type": "boolean"},
tierno7edb6752016-03-21 17:37:52 +0100158 },
sousaedu80135b92021-02-17 15:05:18 +0100159 "required": ["id"],
tierno7edb6752016-03-21 17:37:52 +0100160 }
161 },
162 "required": ["tenant"],
sousaedu80135b92021-02-17 15:05:18 +0100163 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100164}
165
166new_network_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100167 "title": "network response information schema",
tierno7edb6752016-03-21 17:37:52 +0100168 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100169 "type": "object",
170 "properties": {
171 "network": {
172 "type": "object",
173 "properties": {
174 "id": id_schema,
175 "name": name_schema,
176 "type": {
177 "type": "string",
178 "enum": ["bridge_man", "bridge_data", "data", "ptp"],
179 },
180 "shared": {"type": "boolean"},
181 "tenant_id": id_schema,
182 "admin_state_up": {"type": "boolean"},
183 "vlan": vlan1000_schema,
tierno7edb6752016-03-21 17:37:52 +0100184 },
sousaedu80135b92021-02-17 15:05:18 +0100185 "required": ["id"],
tierno7edb6752016-03-21 17:37:52 +0100186 }
187 },
188 "required": ["network"],
sousaedu80135b92021-02-17 15:05:18 +0100189 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100190}
191
192
193# get_network_response_schema = {
194# "title":"get network response information schema",
195# "$schema": "http://json-schema.org/draft-04/schema#",
196# "type":"object",
197# "properties":{
198# "network":{
199# "type":"object",
200# "properties":{
201# "id":id_schema,
202# "name":name_schema,
203# "type":{"type":"string", "enum":["bridge_man","bridge_data","data", "ptp"]},
204# "shared":{"type":"boolean"},
205# "tenant_id":id_schema,
206# "admin_state_up":{"type":"boolean"},
207# "vlan":vlan1000_schema
208# },
209# "required": ["id"]
210# }
211# },
212# "required": ["network"],
213# "additionalProperties": False
214# }
215
216
217new_port_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100218 "title": "port response information schema",
tierno7edb6752016-03-21 17:37:52 +0100219 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100220 "type": "object",
221 "properties": {
222 "port": {
223 "type": "object",
224 "properties": {
225 "id": id_schema,
tierno7edb6752016-03-21 17:37:52 +0100226 },
sousaedu80135b92021-02-17 15:05:18 +0100227 "required": ["id"],
tierno7edb6752016-03-21 17:37:52 +0100228 }
229 },
230 "required": ["port"],
sousaedu80135b92021-02-17 15:05:18 +0100231 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100232}
233
234get_flavor_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100235 "title": "openvim flavors response information schema",
tierno7edb6752016-03-21 17:37:52 +0100236 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100237 "type": "object",
238 "properties": {
239 "flavor": {
240 "type": "object",
241 "properties": {
242 "id": id_schema,
tierno7edb6752016-03-21 17:37:52 +0100243 "name": name_schema,
sousaedu80135b92021-02-17 15:05:18 +0100244 "extended": {"type": "object"},
tierno7edb6752016-03-21 17:37:52 +0100245 },
246 "required": ["id", "name"],
247 }
248 },
249 "required": ["flavor"],
sousaedu80135b92021-02-17 15:05:18 +0100250 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100251}
252
253new_flavor_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100254 "title": "flavor response information schema",
tierno7edb6752016-03-21 17:37:52 +0100255 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100256 "type": "object",
257 "properties": {
258 "flavor": {
259 "type": "object",
260 "properties": {
261 "id": id_schema,
tierno7edb6752016-03-21 17:37:52 +0100262 },
sousaedu80135b92021-02-17 15:05:18 +0100263 "required": ["id"],
tierno7edb6752016-03-21 17:37:52 +0100264 }
265 },
266 "required": ["flavor"],
sousaedu80135b92021-02-17 15:05:18 +0100267 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100268}
269
tiernoae4a8d12016-07-08 12:30:39 +0200270get_image_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100271 "title": "openvim images response information schema",
tiernoae4a8d12016-07-08 12:30:39 +0200272 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100273 "type": "object",
274 "properties": {
275 "image": {
276 "type": "object",
277 "properties": {
278 "id": id_schema,
tiernoae4a8d12016-07-08 12:30:39 +0200279 "name": name_schema,
280 },
281 "required": ["id", "name"],
282 }
283 },
284 "required": ["flavor"],
sousaedu80135b92021-02-17 15:05:18 +0100285 "additionalProperties": False,
tiernoae4a8d12016-07-08 12:30:39 +0200286}
tierno7edb6752016-03-21 17:37:52 +0100287new_image_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100288 "title": "image response information schema",
tierno7edb6752016-03-21 17:37:52 +0100289 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100290 "type": "object",
291 "properties": {
292 "image": {
293 "type": "object",
294 "properties": {
295 "id": id_schema,
tierno7edb6752016-03-21 17:37:52 +0100296 },
sousaedu80135b92021-02-17 15:05:18 +0100297 "required": ["id"],
tierno7edb6752016-03-21 17:37:52 +0100298 }
299 },
300 "required": ["image"],
sousaedu80135b92021-02-17 15:05:18 +0100301 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100302}
303
304new_vminstance_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100305 "title": "server response information schema",
tierno7edb6752016-03-21 17:37:52 +0100306 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100307 "type": "object",
308 "properties": {
309 "server": {
310 "type": "object",
311 "properties": {
312 "id": id_schema,
tierno7edb6752016-03-21 17:37:52 +0100313 },
sousaedu80135b92021-02-17 15:05:18 +0100314 "required": ["id"],
tierno7edb6752016-03-21 17:37:52 +0100315 }
316 },
317 "required": ["server"],
sousaedu80135b92021-02-17 15:05:18 +0100318 "additionalProperties": False,
tierno7edb6752016-03-21 17:37:52 +0100319}
320
321get_processor_rankings_response_schema = {
sousaedu80135b92021-02-17 15:05:18 +0100322 "title": "processor rankings information schema",
tierno7edb6752016-03-21 17:37:52 +0100323 "$schema": "http://json-schema.org/draft-04/schema#",
sousaedu80135b92021-02-17 15:05:18 +0100324 "type": "object",
325 "properties": {
326 "rankings": {
327 "type": "array",
328 "items": {
329 "type": "object",
330 "properties": {"model": description_schema, "value": integer0_schema},
tierno7edb6752016-03-21 17:37:52 +0100331 "additionalProperties": False,
sousaedu80135b92021-02-17 15:05:18 +0100332 "required": ["model", "value"],
333 },
tierno7edb6752016-03-21 17:37:52 +0100334 },
335 "additionalProperties": False,
sousaedu80135b92021-02-17 15:05:18 +0100336 "required": ["rankings"],
337 },
tierno7edb6752016-03-21 17:37:52 +0100338}
339
tierno031ded62019-11-14 14:06:31 +0000340
tierno72774862020-05-04 11:44:15 +0000341class vimconnector(vimconn.VimConnector):
sousaedu80135b92021-02-17 15:05:18 +0100342 def __init__(
343 self,
344 uuid,
345 name,
346 tenant_id,
347 tenant_name,
348 url,
349 url_admin=None,
350 user=None,
351 passwd=None,
352 log_level="DEBUG",
353 config={},
354 persistent_info={},
355 ):
356 vimconn.VimConnector.__init__(
357 self,
358 uuid,
359 name,
360 tenant_id,
361 tenant_name,
362 url,
363 url_admin,
364 user,
365 passwd,
366 log_level,
367 config,
368 )
tierno392f2852016-05-13 12:28:55 +0200369 self.tenant = None
sousaedu80135b92021-02-17 15:05:18 +0100370 self.headers_req = {"content-type": "application/json"}
371 self.logger = logging.getLogger("ro.vim.openvim")
tiernob3d36742017-03-03 23:51:05 +0100372 self.persistent_info = persistent_info
tierno392f2852016-05-13 12:28:55 +0200373 if tenant_id:
374 self.tenant = tenant_id
375
sousaedu80135b92021-02-17 15:05:18 +0100376 def __setitem__(self, index, value):
377 """Set individuals parameters
tierno392f2852016-05-13 12:28:55 +0200378 Throw TypeError, KeyError
sousaedu80135b92021-02-17 15:05:18 +0100379 """
380 if index == "tenant_id":
tierno392f2852016-05-13 12:28:55 +0200381 self.tenant = value
sousaedu80135b92021-02-17 15:05:18 +0100382 elif index == "tenant_name":
tierno392f2852016-05-13 12:28:55 +0200383 self.tenant = None
sousaedu80135b92021-02-17 15:05:18 +0100384 vimconn.VimConnector.__setitem__(self, index, value)
tierno392f2852016-05-13 12:28:55 +0200385
386 def _get_my_tenant(self):
sousaedu80135b92021-02-17 15:05:18 +0100387 """Obtain uuid of my tenant from name"""
tierno392f2852016-05-13 12:28:55 +0200388 if self.tenant:
389 return self.tenant
390
sousaedu80135b92021-02-17 15:05:18 +0100391 url = self.url + "/tenants?name=" + quote(self.tenant_name)
tiernoae4a8d12016-07-08 12:30:39 +0200392 self.logger.info("Getting VIM tenant_id GET %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100393 vim_response = requests.get(url, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +0200394 self._check_http_request_response(vim_response)
395 try:
396 tenant_list = vim_response.json()["tenants"]
397 if len(tenant_list) == 0:
sousaedu80135b92021-02-17 15:05:18 +0100398 raise vimconn.VimConnNotFoundException(
399 "No tenant found for name '{}'".format(self.tenant_name)
400 )
tiernoae4a8d12016-07-08 12:30:39 +0200401 elif len(tenant_list) > 1:
sousaedu80135b92021-02-17 15:05:18 +0100402 raise vimconn.VimConnConflictException(
403 "More that one tenant found for name '{}'".format(self.tenant_name)
404 )
tiernoae4a8d12016-07-08 12:30:39 +0200405 self.tenant = tenant_list[0]["id"]
406 return self.tenant
407 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100408 raise vimconn.VimConnUnexpectedResponse(
409 "Get VIM tenant {} '{}'".format(type(e).__name__, str(e))
410 )
tierno392f2852016-05-13 12:28:55 +0200411
sousaedu80135b92021-02-17 15:05:18 +0100412 def _format_jsonerror(self, http_response):
413 # DEPRECATED, to delete in the future
tierno7edb6752016-03-21 17:37:52 +0100414 try:
415 data = http_response.json()
416 return data["error"]["description"]
sousaedu80135b92021-02-17 15:05:18 +0100417 except Exception:
tierno7edb6752016-03-21 17:37:52 +0100418 return http_response.text
419
420 def _format_in(self, http_response, schema):
sousaedu80135b92021-02-17 15:05:18 +0100421 # DEPRECATED, to delete in the future
tierno7edb6752016-03-21 17:37:52 +0100422 try:
423 client_data = http_response.json()
424 js_v(client_data, schema)
sousaedu80135b92021-02-17 15:05:18 +0100425 # print "Input data: ", str(client_data)
tierno7edb6752016-03-21 17:37:52 +0100426 return True, client_data
venkatamahesh6ecca182017-01-27 23:04:40 +0530427 except js_e.ValidationError as exc:
sousaedu80135b92021-02-17 15:05:18 +0100428 print(
429 "validate_in error, jsonschema exception ", exc.message, "at", exc.path
430 )
431 return False, (
432 "validate_in error, jsonschema exception ",
433 exc.message,
434 "at",
435 exc.path,
436 )
437
tierno7edb6752016-03-21 17:37:52 +0100438 def _remove_extra_items(self, data, schema):
sousaedu80135b92021-02-17 15:05:18 +0100439 deleted = []
tierno7edb6752016-03-21 17:37:52 +0100440 if type(data) is tuple or type(data) is list:
441 for d in data:
sousaedu80135b92021-02-17 15:05:18 +0100442 a = self._remove_extra_items(d, schema["items"])
443 if a is not None:
444 deleted.append(a)
tierno7edb6752016-03-21 17:37:52 +0100445 elif type(data) is dict:
tierno031ded62019-11-14 14:06:31 +0000446 to_delete = []
tierno7edb6752016-03-21 17:37:52 +0100447 for k in data.keys():
sousaedu80135b92021-02-17 15:05:18 +0100448 if "properties" not in schema or k not in schema["properties"].keys():
tierno031ded62019-11-14 14:06:31 +0000449 to_delete.append(k)
tierno7edb6752016-03-21 17:37:52 +0100450 deleted.append(k)
451 else:
sousaedu80135b92021-02-17 15:05:18 +0100452 a = self._remove_extra_items(data[k], schema["properties"][k])
453 if a is not None:
454 deleted.append({k: a})
tierno031ded62019-11-14 14:06:31 +0000455 for k in to_delete:
456 del data[k]
sousaedu80135b92021-02-17 15:05:18 +0100457 if len(deleted) == 0:
458 return None
459 elif len(deleted) == 1:
460 return deleted[0]
tierno7edb6752016-03-21 17:37:52 +0100461 else:
sousaedu80135b92021-02-17 15:05:18 +0100462 return deleted
463
464 def _format_request_exception(self, request_exception):
465 """Transform a request exception into a vimconn exception"""
466 if isinstance(request_exception, js_e.ValidationError):
467 raise vimconn.VimConnUnexpectedResponse(
468 "jsonschema exception '{}' at '{}'".format(
469 request_exception.message, request_exception.path
470 )
471 )
472 elif isinstance(request_exception, requests.exceptions.HTTPError):
473 raise vimconn.VimConnUnexpectedResponse(
474 type(request_exception).__name__ + ": " + str(request_exception)
475 )
476 else:
477 raise vimconn.VimConnConnectionException(
478 type(request_exception).__name__ + ": " + str(request_exception)
479 )
tiernoae4a8d12016-07-08 12:30:39 +0200480
481 def _check_http_request_response(self, request_response):
sousaedu80135b92021-02-17 15:05:18 +0100482 """Raise a vimconn exception if the response is not Ok"""
483 if request_response.status_code >= 200 and request_response.status_code < 300:
tiernoae4a8d12016-07-08 12:30:39 +0200484 return
485 if request_response.status_code == vimconn.HTTP_Unauthorized:
tierno72774862020-05-04 11:44:15 +0000486 raise vimconn.VimConnAuthException(request_response.text)
tiernoae4a8d12016-07-08 12:30:39 +0200487 elif request_response.status_code == vimconn.HTTP_Not_Found:
tierno72774862020-05-04 11:44:15 +0000488 raise vimconn.VimConnNotFoundException(request_response.text)
tiernoae4a8d12016-07-08 12:30:39 +0200489 elif request_response.status_code == vimconn.HTTP_Conflict:
tierno72774862020-05-04 11:44:15 +0000490 raise vimconn.VimConnConflictException(request_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100491 else:
492 raise vimconn.VimConnUnexpectedResponse(
493 "VIM HTTP_response {}, {}".format(
494 request_response.status_code, str(request_response.text)
495 )
496 )
tiernoae4a8d12016-07-08 12:30:39 +0200497
sousaedu80135b92021-02-17 15:05:18 +0100498 def new_tenant(self, tenant_name, tenant_description):
499 """Adds a new tenant to VIM with this name and description, returns the tenant identifier"""
500 # print "VIMConnector: Adding a new tenant to VIM"
501 payload_dict = {
502 "tenant": {
503 "name": tenant_name,
504 "description": tenant_description,
505 "enabled": True,
506 }
507 }
tierno7edb6752016-03-21 17:37:52 +0100508 payload_req = json.dumps(payload_dict)
tierno7edb6752016-03-21 17:37:52 +0100509 try:
sousaedu80135b92021-02-17 15:05:18 +0100510 url = self.url_admin + "/tenants"
tiernoae4a8d12016-07-08 12:30:39 +0200511 self.logger.info("Adding a new tenant %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100512 vim_response = requests.post(
513 url, headers=self.headers_req, data=payload_req
514 )
tiernoae4a8d12016-07-08 12:30:39 +0200515 self._check_http_request_response(vim_response)
516 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100517 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200518 response = vim_response.json()
519 js_v(response, new_tenant_response_schema)
sousaedu80135b92021-02-17 15:05:18 +0100520 # r = self._remove_extra_items(response, new_tenant_response_schema)
521 # if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +0200522 # self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +0100523 tenant_id = response["tenant"]["id"]
tiernoae4a8d12016-07-08 12:30:39 +0200524 return tenant_id
525 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
526 self._format_request_exception(e)
tierno7edb6752016-03-21 17:37:52 +0100527
sousaedu80135b92021-02-17 15:05:18 +0100528 def delete_tenant(self, tenant_id):
529 """Delete a tenant from VIM. Returns the old tenant identifier"""
tierno7edb6752016-03-21 17:37:52 +0100530 try:
sousaedu80135b92021-02-17 15:05:18 +0100531 url = self.url_admin + "/tenants/" + tenant_id
tiernoae4a8d12016-07-08 12:30:39 +0200532 self.logger.info("Delete a tenant DELETE %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100533 vim_response = requests.delete(url, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +0200534 self._check_http_request_response(vim_response)
535 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100536 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200537 return tenant_id
538 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
539 self._format_request_exception(e)
tierno7edb6752016-03-21 17:37:52 +0100540
541 def get_tenant_list(self, filter_dict={}):
sousaedu80135b92021-02-17 15:05:18 +0100542 """Obtain tenants of VIM
tiernoae4a8d12016-07-08 12:30:39 +0200543 filter_dict can contain the following keys:
544 name: filter by tenant name
545 id: filter by tenant uuid/id
546 <other VIM specific>
547 Returns the tenant list of dictionaries: [{'name':'<name>, 'id':'<id>, ...}, ...]
sousaedu80135b92021-02-17 15:05:18 +0100548 """
549 filterquery = []
550 filterquery_text = ""
551 for k, v in filter_dict.items():
552 filterquery.append(str(k) + "=" + str(v))
553 if len(filterquery) > 0:
554 filterquery_text = "?" + "&".join(filterquery)
tierno7edb6752016-03-21 17:37:52 +0100555 try:
sousaedu80135b92021-02-17 15:05:18 +0100556 url = self.url + "/tenants" + filterquery_text
tiernoae4a8d12016-07-08 12:30:39 +0200557 self.logger.info("get_tenant_list GET %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100558 vim_response = requests.get(url, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +0200559 self._check_http_request_response(vim_response)
560 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100561 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200562 return vim_response.json()["tenants"]
563 except requests.exceptions.RequestException as e:
564 self._format_request_exception(e)
565
sousaedu80135b92021-02-17 15:05:18 +0100566 def new_network(
567 self,
568 net_name,
569 net_type,
570 ip_profile=None,
571 shared=False,
572 provider_network_profile=None,
573 ): # , **vim_specific):
garciadeblasebd66722019-01-31 16:01:31 +0000574 """Adds a tenant network to VIM
575 Params:
576 'net_name': name of the network
577 'net_type': one of:
578 'bridge': overlay isolated network
579 'data': underlay E-LAN network for Passthrough and SRIOV interfaces
580 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces.
581 'ip_profile': is a dict containing the IP parameters of the network
582 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented)
583 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y
584 'gateway_address': (Optional) ip_schema, that is X.X.X.X
585 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X]
586 'dhcp_enabled': True or False
587 'dhcp_start_address': ip_schema, first IP to grant
588 'dhcp_count': number of IPs to grant.
589 'shared': if this network can be seen/use by other tenants/organization
kbsuba85c54d2019-10-17 16:30:32 +0000590 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk}
garciadeblasebd66722019-01-31 16:01:31 +0000591 Returns a tuple with the network identifier and created_items, or raises an exception on error
592 created_items can be None or a dictionary where this method can include key-values that will be passed to
593 the method delete_network. Can be used to store created segments, created l2gw connections, etc.
594 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
595 as not present.
596 """
tiernoae4a8d12016-07-08 12:30:39 +0200597 try:
kbsuba85c54d2019-10-17 16:30:32 +0000598 vlan = None
599 if provider_network_profile:
600 vlan = provider_network_profile.get("segmentation-id")
garciadeblasebd66722019-01-31 16:01:31 +0000601 created_items = {}
tiernoae4a8d12016-07-08 12:30:39 +0200602 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100603 if net_type == "bridge":
604 net_type = "bridge_data"
605 payload_req = {
606 "name": net_name,
607 "type": net_type,
608 "tenant_id": self.tenant,
609 "shared": shared,
610 }
tiernoa7d34d02017-02-23 14:42:07 +0100611 if vlan:
612 payload_req["provider:vlan"] = vlan
613 # payload_req.update(vim_specific)
sousaedu80135b92021-02-17 15:05:18 +0100614 url = self.url + "/networks"
615 self.logger.info(
616 "Adding a new network POST: %s DATA: %s", url, str(payload_req)
617 )
618 vim_response = requests.post(
619 url, headers=self.headers_req, data=json.dumps({"network": payload_req})
620 )
tiernoae4a8d12016-07-08 12:30:39 +0200621 self._check_http_request_response(vim_response)
622 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100623 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200624 response = vim_response.json()
625 js_v(response, new_network_response_schema)
sousaedu80135b92021-02-17 15:05:18 +0100626 # r = self._remove_extra_items(response, new_network_response_schema)
627 # if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +0200628 # self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +0100629 network_id = response["network"]["id"]
garciadeblasebd66722019-01-31 16:01:31 +0000630 return network_id, created_items
tiernoae4a8d12016-07-08 12:30:39 +0200631 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
632 self._format_request_exception(e)
sousaedu80135b92021-02-17 15:05:18 +0100633
tierno7edb6752016-03-21 17:37:52 +0100634 def get_network_list(self, filter_dict={}):
sousaedu80135b92021-02-17 15:05:18 +0100635 """Obtain tenant networks of VIM
tierno7edb6752016-03-21 17:37:52 +0100636 Filter_dict can be:
637 name: network name
638 id: network uuid
tiernoae4a8d12016-07-08 12:30:39 +0200639 public: boolean
tierno7edb6752016-03-21 17:37:52 +0100640 tenant_id: tenant
641 admin_state_up: boolean
642 status: 'ACTIVE'
643 Returns the network list of dictionaries
sousaedu80135b92021-02-17 15:05:18 +0100644 """
tierno7edb6752016-03-21 17:37:52 +0100645 try:
sousaedu80135b92021-02-17 15:05:18 +0100646 if "tenant_id" not in filter_dict:
tiernoae4a8d12016-07-08 12:30:39 +0200647 filter_dict["tenant_id"] = self._get_my_tenant()
648 elif not filter_dict["tenant_id"]:
649 del filter_dict["tenant_id"]
sousaedu80135b92021-02-17 15:05:18 +0100650 filterquery = []
651 filterquery_text = ""
652 for k, v in filter_dict.items():
653 filterquery.append(str(k) + "=" + str(v))
654 if len(filterquery) > 0:
655 filterquery_text = "?" + "&".join(filterquery)
656 url = self.url + "/networks" + filterquery_text
tiernoae4a8d12016-07-08 12:30:39 +0200657 self.logger.info("Getting network list GET %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100658 vim_response = requests.get(url, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +0200659 self._check_http_request_response(vim_response)
660 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100661 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200662 response = vim_response.json()
sousaedu80135b92021-02-17 15:05:18 +0100663 return response["networks"]
tiernoae4a8d12016-07-08 12:30:39 +0200664 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
665 self._format_request_exception(e)
tierno7edb6752016-03-21 17:37:52 +0100666
tiernoae4a8d12016-07-08 12:30:39 +0200667 def get_network(self, net_id):
sousaedu80135b92021-02-17 15:05:18 +0100668 """Obtain network details of network id"""
tiernoae4a8d12016-07-08 12:30:39 +0200669 try:
sousaedu80135b92021-02-17 15:05:18 +0100670 url = self.url + "/networks/" + net_id
tiernoae4a8d12016-07-08 12:30:39 +0200671 self.logger.info("Getting network GET %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100672 vim_response = requests.get(url, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +0200673 self._check_http_request_response(vim_response)
674 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100675 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200676 response = vim_response.json()
sousaedu80135b92021-02-17 15:05:18 +0100677 return response["network"]
tiernoae4a8d12016-07-08 12:30:39 +0200678 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
679 self._format_request_exception(e)
sousaedu80135b92021-02-17 15:05:18 +0100680
garciadeblasebd66722019-01-31 16:01:31 +0000681 def delete_network(self, net_id, created_items=None):
682 """
683 Removes a tenant network from VIM and its associated elements
684 :param net_id: VIM identifier of the network, provided by method new_network
685 :param created_items: dictionary with extra items to be deleted. provided by method new_network
686 Returns the network identifier or raises an exception upon error or when network is not found
687 """
tierno392f2852016-05-13 12:28:55 +0200688 try:
689 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100690 url = self.url + "/networks/" + net_id
tiernoae4a8d12016-07-08 12:30:39 +0200691 self.logger.info("Deleting VIM network DELETE %s", url)
692 vim_response = requests.delete(url, headers=self.headers_req)
693 self._check_http_request_response(vim_response)
sousaedu80135b92021-02-17 15:05:18 +0100694 # self.logger.debug(vim_response.text)
695 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200696 return net_id
697 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
698 self._format_request_exception(e)
tierno7edb6752016-03-21 17:37:52 +0100699
tiernoae4a8d12016-07-08 12:30:39 +0200700 def get_flavor(self, flavor_id):
sousaedu80135b92021-02-17 15:05:18 +0100701 """Obtain flavor details from the VIM"""
tierno392f2852016-05-13 12:28:55 +0200702 try:
703 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100704 url = self.url + "/" + self.tenant + "/flavors/" + flavor_id
tiernoae4a8d12016-07-08 12:30:39 +0200705 self.logger.info("Getting flavor GET %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100706 vim_response = requests.get(url, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +0200707 self._check_http_request_response(vim_response)
708 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100709 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200710 response = vim_response.json()
711 js_v(response, get_flavor_response_schema)
712 r = self._remove_extra_items(response, get_flavor_response_schema)
sousaedu80135b92021-02-17 15:05:18 +0100713 if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +0200714 self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +0100715 return response["flavor"]
tiernoae4a8d12016-07-08 12:30:39 +0200716 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
717 self._format_request_exception(e)
sousaedu80135b92021-02-17 15:05:18 +0100718
tiernoae4a8d12016-07-08 12:30:39 +0200719 def new_flavor(self, flavor_data):
sousaedu80135b92021-02-17 15:05:18 +0100720 """Adds a tenant flavor to VIM"""
721 """Returns the flavor identifier"""
tierno392f2852016-05-13 12:28:55 +0200722 try:
tierno7432e7c2017-01-04 16:54:37 +0100723 new_flavor_dict = flavor_data.copy()
sousaedu80135b92021-02-17 15:05:18 +0100724 for device in new_flavor_dict.get("extended", {}).get("devices", ()):
725 if "image name" in device:
726 del device["image name"]
727 if "name" in device:
728 del device["name"]
729 numas = new_flavor_dict.get("extended", {}).get("numas")
tierno66eba6e2017-11-10 17:09:18 +0100730 if numas:
731 numa = numas[0]
732 # translate memory, cpus to EPA
sousaedu80135b92021-02-17 15:05:18 +0100733 if (
734 "cores" not in numa
735 and "threads" not in numa
736 and "paired-threads" not in numa
737 ):
tierno66eba6e2017-11-10 17:09:18 +0100738 numa["paired-threads"] = new_flavor_dict["vcpus"]
739 if "memory" not in numa:
tierno7d782ef2019-10-04 12:56:31 +0000740 numa["memory"] = int(math.ceil(new_flavor_dict["ram"] / 1024.0))
tierno66eba6e2017-11-10 17:09:18 +0100741 for iface in numa.get("interfaces", ()):
742 if not iface.get("bandwidth"):
743 iface["bandwidth"] = "1 Mbps"
744
tierno7432e7c2017-01-04 16:54:37 +0100745 new_flavor_dict["name"] = flavor_data["name"][:64]
tierno392f2852016-05-13 12:28:55 +0200746 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100747 payload_req = json.dumps({"flavor": new_flavor_dict})
748 url = self.url + "/" + self.tenant + "/flavors"
tiernoae4a8d12016-07-08 12:30:39 +0200749 self.logger.info("Adding a new VIM flavor POST %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100750 vim_response = requests.post(
751 url, headers=self.headers_req, data=payload_req
752 )
tiernoae4a8d12016-07-08 12:30:39 +0200753 self._check_http_request_response(vim_response)
754 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100755 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200756 response = vim_response.json()
757 js_v(response, new_flavor_response_schema)
758 r = self._remove_extra_items(response, new_flavor_response_schema)
sousaedu80135b92021-02-17 15:05:18 +0100759 if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +0200760 self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +0100761 flavor_id = response["flavor"]["id"]
tiernoae4a8d12016-07-08 12:30:39 +0200762 return flavor_id
763 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
764 self._format_request_exception(e)
tierno7edb6752016-03-21 17:37:52 +0100765
sousaedu80135b92021-02-17 15:05:18 +0100766 def delete_flavor(self, flavor_id):
767 """Deletes a tenant flavor from VIM"""
768 """Returns the old flavor_id"""
tierno392f2852016-05-13 12:28:55 +0200769 try:
770 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100771 url = self.url + "/" + self.tenant + "/flavors/" + flavor_id
tiernoae4a8d12016-07-08 12:30:39 +0200772 self.logger.info("Deleting VIM flavor DELETE %s", url)
773 vim_response = requests.delete(url, headers=self.headers_req)
774 self._check_http_request_response(vim_response)
sousaedu80135b92021-02-17 15:05:18 +0100775 # self.logger.debug(vim_response.text)
776 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200777 return flavor_id
778 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
779 self._format_request_exception(e)
780
781 def get_image(self, image_id):
sousaedu80135b92021-02-17 15:05:18 +0100782 """Obtain image details from the VIM"""
tierno7edb6752016-03-21 17:37:52 +0100783 try:
tiernoae4a8d12016-07-08 12:30:39 +0200784 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100785 url = self.url + "/" + self.tenant + "/images/" + image_id
tiernoae4a8d12016-07-08 12:30:39 +0200786 self.logger.info("Getting image GET %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100787 vim_response = requests.get(url, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +0200788 self._check_http_request_response(vim_response)
789 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100790 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200791 response = vim_response.json()
792 js_v(response, get_image_response_schema)
793 r = self._remove_extra_items(response, get_image_response_schema)
sousaedu80135b92021-02-17 15:05:18 +0100794 if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +0200795 self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +0100796 return response["image"]
tiernoae4a8d12016-07-08 12:30:39 +0200797 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
798 self._format_request_exception(e)
799
sousaedu80135b92021-02-17 15:05:18 +0100800 def new_image(self, image_dict):
801 """ Adds a tenant image to VIM, returns image_id"""
tiernoae4a8d12016-07-08 12:30:39 +0200802 try:
803 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100804 new_image_dict = {"name": image_dict["name"][:64]}
805 if image_dict.get("description"):
806 new_image_dict["description"] = image_dict["description"]
807 if image_dict.get("metadata"):
808 new_image_dict["metadata"] = yaml.load(
809 image_dict["metadata"], Loader=yaml.SafeLoader
810 )
811 if image_dict.get("location"):
812 new_image_dict["path"] = image_dict["location"]
813 payload_req = json.dumps({"image": new_image_dict})
814 url = self.url + "/" + self.tenant + "/images"
tiernoae4a8d12016-07-08 12:30:39 +0200815 self.logger.info("Adding a new VIM image POST %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100816 vim_response = requests.post(
817 url, headers=self.headers_req, data=payload_req
818 )
tiernoae4a8d12016-07-08 12:30:39 +0200819 self._check_http_request_response(vim_response)
820 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100821 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200822 response = vim_response.json()
823 js_v(response, new_image_response_schema)
824 r = self._remove_extra_items(response, new_image_response_schema)
sousaedu80135b92021-02-17 15:05:18 +0100825 if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +0200826 self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +0100827 image_id = response["image"]["id"]
tiernoae4a8d12016-07-08 12:30:39 +0200828 return image_id
829 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
830 self._format_request_exception(e)
sousaedu80135b92021-02-17 15:05:18 +0100831
tiernoae4a8d12016-07-08 12:30:39 +0200832 def delete_image(self, image_id):
sousaedu80135b92021-02-17 15:05:18 +0100833 """Deletes a tenant image from VIM"""
834 """Returns the deleted image_id"""
tiernoae4a8d12016-07-08 12:30:39 +0200835 try:
836 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100837 url = self.url + "/" + self.tenant + "/images/" + image_id
tiernoae4a8d12016-07-08 12:30:39 +0200838 self.logger.info("Deleting VIM image DELETE %s", url)
839 vim_response = requests.delete(url, headers=self.headers_req)
840 self._check_http_request_response(vim_response)
sousaedu80135b92021-02-17 15:05:18 +0100841 # self.logger.debug(vim_response.text)
842 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200843 return image_id
844 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
845 self._format_request_exception(e)
846
tiernoae4a8d12016-07-08 12:30:39 +0200847 def get_image_id_from_path(self, path):
sousaedu80135b92021-02-17 15:05:18 +0100848 """Get the image id from image path in the VIM database. Returns the image_id"""
tiernoae4a8d12016-07-08 12:30:39 +0200849 try:
850 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100851 url = self.url + "/" + self.tenant + "/images?path=" + quote(path)
tiernoae4a8d12016-07-08 12:30:39 +0200852 self.logger.info("Getting images GET %s", url)
853 vim_response = requests.get(url)
854 self._check_http_request_response(vim_response)
855 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100856 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +0200857 response = vim_response.json()
858 js_v(response, get_images_response_schema)
sousaedu80135b92021-02-17 15:05:18 +0100859 # r = self._remove_extra_items(response, get_images_response_schema)
860 # if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +0200861 # self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +0100862 if len(response["images"]) == 0:
863 raise vimconn.VimConnNotFoundException(
864 "Image not found at VIM with path '{}'".format(path)
865 )
866 elif len(response["images"]) > 1:
867 raise vimconn.VimConnConflictException(
868 "More than one image found at VIM with path '{}'".format(path)
869 )
870 return response["images"][0]["id"]
tiernoae4a8d12016-07-08 12:30:39 +0200871 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
872 self._format_request_exception(e)
873
garciadeblasb69fa9f2016-09-28 12:04:10 +0200874 def get_image_list(self, filter_dict={}):
sousaedu80135b92021-02-17 15:05:18 +0100875 """Obtain tenant images from VIM
garciadeblasb69fa9f2016-09-28 12:04:10 +0200876 Filter_dict can be:
877 name: image name
878 id: image uuid
879 checksum: image checksum
880 location: image path
881 Returns the image list of dictionaries:
882 [{<the fields at Filter_dict plus some VIM specific>}, ...]
883 List can be empty
sousaedu80135b92021-02-17 15:05:18 +0100884 """
garciadeblasb69fa9f2016-09-28 12:04:10 +0200885 try:
886 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100887 filterquery = []
888 filterquery_text = ""
889 for k, v in filter_dict.items():
890 filterquery.append(str(k) + "=" + str(v))
891 if len(filterquery) > 0:
892 filterquery_text = "?" + "&".join(filterquery)
893 url = self.url + "/" + self.tenant + "/images" + filterquery_text
garciadeblasb69fa9f2016-09-28 12:04:10 +0200894 self.logger.info("Getting image list GET %s", url)
sousaedu80135b92021-02-17 15:05:18 +0100895 vim_response = requests.get(url, headers=self.headers_req)
garciadeblasb69fa9f2016-09-28 12:04:10 +0200896 self._check_http_request_response(vim_response)
897 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +0100898 # print json.dumps(vim_response.json(), indent=4)
garciadeblasb69fa9f2016-09-28 12:04:10 +0200899 response = vim_response.json()
sousaedu80135b92021-02-17 15:05:18 +0100900 return response["images"]
garciadeblasb69fa9f2016-09-28 12:04:10 +0200901 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
902 self._format_request_exception(e)
903
tiernoae4a8d12016-07-08 12:30:39 +0200904 def new_vminstancefromJSON(self, vm_data):
sousaedu80135b92021-02-17 15:05:18 +0100905 """Adds a VM instance to VIM"""
906 """Returns the instance identifier"""
tierno392f2852016-05-13 12:28:55 +0200907 try:
908 self._get_my_tenant()
909 except Exception as e:
910 return -vimconn.HTTP_Not_Found, str(e)
tierno7d782ef2019-10-04 12:56:31 +0000911 print("VIMConnector: Adding a new VM instance from JSON to VIM")
tierno7edb6752016-03-21 17:37:52 +0100912 payload_req = vm_data
913 try:
sousaedu80135b92021-02-17 15:05:18 +0100914 vim_response = requests.post(
915 self.url + "/" + self.tenant + "/servers",
916 headers=self.headers_req,
917 data=payload_req,
918 )
venkatamahesh6ecca182017-01-27 23:04:40 +0530919 except requests.exceptions.RequestException as e:
sousaedu80135b92021-02-17 15:05:18 +0100920 print("new_vminstancefromJSON Exception: ", e.args)
tierno7edb6752016-03-21 17:37:52 +0100921 return -vimconn.HTTP_Not_Found, str(e.args[0])
tierno7d782ef2019-10-04 12:56:31 +0000922 # print vim_response
sousaedu80135b92021-02-17 15:05:18 +0100923 # print vim_response.status_code
tierno7edb6752016-03-21 17:37:52 +0100924 if vim_response.status_code == 200:
sousaedu80135b92021-02-17 15:05:18 +0100925 # print vim_response.json()
926 # print json.dumps(vim_response.json(), indent=4)
927 res, http_content = self._format_in(vim_response, new_image_response_schema)
928 # print http_content
tierno7edb6752016-03-21 17:37:52 +0100929 if res:
930 r = self._remove_extra_items(http_content, new_image_response_schema)
sousaedu80135b92021-02-17 15:05:18 +0100931 if r is not None:
932 print("Warning: remove extra items ", r)
933 # print http_content
934 vminstance_id = http_content["server"]["id"]
935 print("Tenant image id: ", vminstance_id)
936 return vim_response.status_code, vminstance_id
937 else:
938 return -vimconn.HTTP_Bad_Request, http_content
tierno7edb6752016-03-21 17:37:52 +0100939 else:
sousaedu80135b92021-02-17 15:05:18 +0100940 # print vim_response.text
tierno7edb6752016-03-21 17:37:52 +0100941 jsonerror = self._format_jsonerror(vim_response)
tierno7d782ef2019-10-04 12:56:31 +0000942 text = 'Error in VIM "{}": not possible to add new vm instance. HTTP Response: {}. Error: {}'.format(
sousaedu80135b92021-02-17 15:05:18 +0100943 self.url, vim_response.status_code, jsonerror
944 )
945 # print text
946 return -vim_response.status_code, text
tierno7edb6752016-03-21 17:37:52 +0100947
sousaedu80135b92021-02-17 15:05:18 +0100948 def new_vminstance(
949 self,
950 name,
951 description,
952 start,
953 image_id,
954 flavor_id,
955 net_list,
956 cloud_config=None,
957 disk_list=None,
958 availability_zone_index=None,
959 availability_zone_list=None,
960 ):
tierno66eba6e2017-11-10 17:09:18 +0100961 """Adds a VM instance to VIM
tierno7edb6752016-03-21 17:37:52 +0100962 Params:
963 start: indicates if VM must start or boot in pause mode. Ignored
964 image_id,flavor_id: image and flavor uuid
965 net_list: list of interfaces, each one is a dictionary with:
966 name:
967 net_id: network uuid to connect
968 vpci: virtual vcpi to assign
garciadeblasc4f4d732018-10-25 18:17:24 +0200969 model: interface model, virtio, e1000, ...
sousaedu80135b92021-02-17 15:05:18 +0100970 mac_address:
tierno7edb6752016-03-21 17:37:52 +0100971 use: 'data', 'bridge', 'mgmt'
tierno66eba6e2017-11-10 17:09:18 +0100972 type: 'virtual', 'PCI-PASSTHROUGH'('PF'), 'SR-IOV'('VF'), 'VFnotShared'
tierno7edb6752016-03-21 17:37:52 +0100973 vim_id: filled/added by this function
974 #TODO ip, security groups
tierno98e909c2017-10-14 13:27:03 +0200975 Returns a tuple with the instance identifier and created_items or raises an exception on error
976 created_items can be None or a dictionary where this method can include key-values that will be passed to
977 the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc.
978 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
979 as not present.
tierno66eba6e2017-11-10 17:09:18 +0100980 """
sousaedu80135b92021-02-17 15:05:18 +0100981 self.logger.debug(
982 "new_vminstance input: image='%s' flavor='%s' nics='%s'",
983 image_id,
984 flavor_id,
985 str(net_list),
986 )
tierno392f2852016-05-13 12:28:55 +0200987 try:
988 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +0100989 # net_list = []
990 # for k,v in net_dict.items():
991 # print k,v
992 # net_list.append('{"name":"' + k + '", "uuid":"' + v + '"}')
993 # net_list_string = ', '.join(net_list)
994 virtio_net_list = []
tiernoae4a8d12016-07-08 12:30:39 +0200995 for net in net_list:
tierno7edb6752016-03-21 17:37:52 +0100996 if not net.get("net_id"):
997 continue
sousaedu80135b92021-02-17 15:05:18 +0100998 net_dict = {"uuid": net["net_id"]}
tierno66eba6e2017-11-10 17:09:18 +0100999 if net.get("type"):
1000 if net["type"] == "SR-IOV":
1001 net_dict["type"] = "VF"
1002 elif net["type"] == "PCI-PASSTHROUGH":
1003 net_dict["type"] = "PF"
1004 else:
1005 net_dict["type"] = net["type"]
1006 if net.get("name"):
1007 net_dict["name"] = net["name"]
1008 if net.get("vpci"):
1009 net_dict["vpci"] = net["vpci"]
1010 if net.get("model"):
garciadeblas31e141b2018-10-25 18:33:19 +02001011 if net["model"] == "VIRTIO" or net["model"] == "paravirt":
tierno66eba6e2017-11-10 17:09:18 +01001012 net_dict["model"] = "virtio"
1013 else:
1014 net_dict["model"] = net["model"]
1015 if net.get("mac_address"):
1016 net_dict["mac_address"] = net["mac_address"]
tierno41a69812018-02-16 14:34:33 +01001017 if net.get("ip_address"):
1018 net_dict["ip_address"] = net["ip_address"]
tiernoae4a8d12016-07-08 12:30:39 +02001019 virtio_net_list.append(net_dict)
sousaedu80135b92021-02-17 15:05:18 +01001020 payload_dict = {
1021 "name": name[:64],
1022 "description": description,
1023 "imageRef": image_id,
1024 "flavorRef": flavor_id,
1025 "networks": virtio_net_list,
1026 }
1027 if start is not None:
tiernoae4a8d12016-07-08 12:30:39 +02001028 payload_dict["start"] = start
1029 payload_req = json.dumps({"server": payload_dict})
sousaedu80135b92021-02-17 15:05:18 +01001030 url = self.url + "/" + self.tenant + "/servers"
tiernoae4a8d12016-07-08 12:30:39 +02001031 self.logger.info("Adding a new vm POST %s DATA %s", url, payload_req)
sousaedu80135b92021-02-17 15:05:18 +01001032 vim_response = requests.post(
1033 url, headers=self.headers_req, data=payload_req
1034 )
tiernoae4a8d12016-07-08 12:30:39 +02001035 self._check_http_request_response(vim_response)
1036 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +01001037 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +02001038 response = vim_response.json()
1039 js_v(response, new_vminstance_response_schema)
sousaedu80135b92021-02-17 15:05:18 +01001040 # r = self._remove_extra_items(response, new_vminstance_response_schema)
1041 # if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +02001042 # self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +01001043 vminstance_id = response["server"]["id"]
tiernoae4a8d12016-07-08 12:30:39 +02001044
sousaedu80135b92021-02-17 15:05:18 +01001045 # connect data plane interfaces to network
tiernoae4a8d12016-07-08 12:30:39 +02001046 for net in net_list:
sousaedu80135b92021-02-17 15:05:18 +01001047 if net["type"] == "virtual":
tiernoae4a8d12016-07-08 12:30:39 +02001048 if not net.get("net_id"):
1049 continue
sousaedu80135b92021-02-17 15:05:18 +01001050 for iface in response["server"]["networks"]:
tiernoae4a8d12016-07-08 12:30:39 +02001051 if "name" in net:
sousaedu80135b92021-02-17 15:05:18 +01001052 if net["name"] == iface["name"]:
1053 net["vim_id"] = iface["iface_id"]
tiernoae4a8d12016-07-08 12:30:39 +02001054 break
1055 elif "net_id" in net:
sousaedu80135b92021-02-17 15:05:18 +01001056 if net["net_id"] == iface["net_id"]:
1057 net["vim_id"] = iface["iface_id"]
tiernoae4a8d12016-07-08 12:30:39 +02001058 break
sousaedu80135b92021-02-17 15:05:18 +01001059 else: # dataplane
1060 for numa in response["server"].get("extended", {}).get("numas", ()):
1061 for iface in numa.get("interfaces", ()):
1062 if net["name"] == iface["name"]:
1063 net["vim_id"] = iface["iface_id"]
1064 # Code bellow is not needed, current openvim connect dataplane interfaces
1065 # if net.get("net_id"):
1066 # connect dataplane interface
tiernoae4a8d12016-07-08 12:30:39 +02001067 # result, port_id = self.connect_port_network(iface['iface_id'], net["net_id"])
1068 # if result < 0:
sousaedu80135b92021-02-17 15:05:18 +01001069 # error_text = "Error attaching port %s to network %s: %s." % (iface['iface_id']
1070 # , net["net_id"], port_id)
tiernoae4a8d12016-07-08 12:30:39 +02001071 # print "new_vminstance: " + error_text
1072 # self.delete_vminstance(vminstance_id)
1073 # return result, error_text
1074 break
sousaedu80135b92021-02-17 15:05:18 +01001075
tierno98e909c2017-10-14 13:27:03 +02001076 return vminstance_id, None
tiernoae4a8d12016-07-08 12:30:39 +02001077 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
1078 self._format_request_exception(e)
sousaedu80135b92021-02-17 15:05:18 +01001079
tiernoae4a8d12016-07-08 12:30:39 +02001080 def get_vminstance(self, vm_id):
sousaedu80135b92021-02-17 15:05:18 +01001081 """Returns the VM instance information from VIM"""
tierno392f2852016-05-13 12:28:55 +02001082 try:
1083 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +01001084 url = self.url + "/" + self.tenant + "/servers/" + vm_id
tiernoae4a8d12016-07-08 12:30:39 +02001085 self.logger.info("Getting vm GET %s", url)
sousaedu80135b92021-02-17 15:05:18 +01001086 vim_response = requests.get(url, headers=self.headers_req)
1087 vim_response = requests.get(url, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +02001088 self._check_http_request_response(vim_response)
1089 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +01001090 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +02001091 response = vim_response.json()
1092 js_v(response, new_vminstance_response_schema)
sousaedu80135b92021-02-17 15:05:18 +01001093 # r = self._remove_extra_items(response, new_vminstance_response_schema)
1094 # if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +02001095 # self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +01001096 return response["server"]
tiernoae4a8d12016-07-08 12:30:39 +02001097 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
1098 self._format_request_exception(e)
sousaedu80135b92021-02-17 15:05:18 +01001099
tierno98e909c2017-10-14 13:27:03 +02001100 def delete_vminstance(self, vm_id, created_items=None):
sousaedu80135b92021-02-17 15:05:18 +01001101 """Removes a VM instance from VIM, returns the deleted vm_id"""
tierno392f2852016-05-13 12:28:55 +02001102 try:
1103 self._get_my_tenant()
sousaedu80135b92021-02-17 15:05:18 +01001104 url = self.url + "/" + self.tenant + "/servers/" + vm_id
tiernoae4a8d12016-07-08 12:30:39 +02001105 self.logger.info("Deleting VIM vm DELETE %s", url)
1106 vim_response = requests.delete(url, headers=self.headers_req)
1107 self._check_http_request_response(vim_response)
sousaedu80135b92021-02-17 15:05:18 +01001108 # self.logger.debug(vim_response.text)
1109 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +02001110 return vm_id
1111 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
1112 self._format_request_exception(e)
1113
1114 def refresh_vms_status(self, vm_list):
sousaedu80135b92021-02-17 15:05:18 +01001115 """Refreshes the status of the virtual machines"""
tierno7edb6752016-03-21 17:37:52 +01001116 try:
tiernoae4a8d12016-07-08 12:30:39 +02001117 self._get_my_tenant()
1118 except requests.exceptions.RequestException as e:
1119 self._format_request_exception(e)
sousaedu80135b92021-02-17 15:05:18 +01001120 vm_dict = {}
tiernoae4a8d12016-07-08 12:30:39 +02001121 for vm_id in vm_list:
sousaedu80135b92021-02-17 15:05:18 +01001122 vm = {}
1123 # print "VIMConnector refresh_tenant_vms and nets: Getting tenant VM instance information from VIM"
tiernoae4a8d12016-07-08 12:30:39 +02001124 try:
sousaedu80135b92021-02-17 15:05:18 +01001125 url = self.url + "/" + self.tenant + "/servers/" + vm_id
tiernoae4a8d12016-07-08 12:30:39 +02001126 self.logger.info("Getting vm GET %s", url)
sousaedu80135b92021-02-17 15:05:18 +01001127 vim_response = requests.get(url, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +02001128 self._check_http_request_response(vim_response)
1129 response = vim_response.json()
1130 js_v(response, new_vminstance_response_schema)
sousaedu80135b92021-02-17 15:05:18 +01001131 if response["server"]["status"] in vmStatus2manoFormat:
1132 vm["status"] = vmStatus2manoFormat[response["server"]["status"]]
tiernoae4a8d12016-07-08 12:30:39 +02001133 else:
sousaedu80135b92021-02-17 15:05:18 +01001134 vm["status"] = "OTHER"
1135 vm["error_msg"] = (
1136 "VIM status reported " + response["server"]["status"]
1137 )
1138 if response["server"].get("last_error"):
1139 vm["error_msg"] = response["server"]["last_error"]
1140 vm["vim_info"] = yaml.safe_dump(response["server"])
1141 # get interfaces info
tiernoae4a8d12016-07-08 12:30:39 +02001142 try:
1143 management_ip = False
sousaedu80135b92021-02-17 15:05:18 +01001144 url2 = self.url + "/ports?device_id=" + quote(vm_id)
tiernoae4a8d12016-07-08 12:30:39 +02001145 self.logger.info("Getting PORTS GET %s", url2)
sousaedu80135b92021-02-17 15:05:18 +01001146 vim_response2 = requests.get(url2, headers=self.headers_req)
tiernoae4a8d12016-07-08 12:30:39 +02001147 self._check_http_request_response(vim_response2)
1148 client_data = vim_response2.json()
1149 if isinstance(client_data.get("ports"), list):
sousaedu80135b92021-02-17 15:05:18 +01001150 vm["interfaces"] = []
tiernoae4a8d12016-07-08 12:30:39 +02001151 for port in client_data.get("ports"):
sousaedu80135b92021-02-17 15:05:18 +01001152 interface = {}
1153 interface["vim_info"] = yaml.safe_dump(port)
tiernoae4a8d12016-07-08 12:30:39 +02001154 interface["mac_address"] = port.get("mac_address")
tierno8e995ce2016-09-22 08:13:00 +00001155 interface["vim_net_id"] = port.get("network_id")
tiernoae4a8d12016-07-08 12:30:39 +02001156 interface["vim_interface_id"] = port["id"]
1157 interface["ip_address"] = port.get("ip_address")
1158 if interface["ip_address"]:
1159 management_ip = True
1160 if interface["ip_address"] == "0.0.0.0":
1161 interface["ip_address"] = None
1162 vm["interfaces"].append(interface)
tierno7edb6752016-03-21 17:37:52 +01001163
sousaedu80135b92021-02-17 15:05:18 +01001164 except Exception as e:
1165 self.logger.error(
1166 "refresh_vms_and_nets. Port get %s: %s",
1167 type(e).__name__,
1168 str(e),
1169 )
1170
1171 if vm["status"] == "ACTIVE" and not management_ip:
1172 vm["status"] = "ACTIVE:NoMgmtIP"
1173
tierno72774862020-05-04 11:44:15 +00001174 except vimconn.VimConnNotFoundException as e:
tiernoae4a8d12016-07-08 12:30:39 +02001175 self.logger.error("Exception getting vm status: %s", str(e))
sousaedu80135b92021-02-17 15:05:18 +01001176 vm["status"] = "DELETED"
1177 vm["error_msg"] = str(e)
1178 except (
1179 requests.exceptions.RequestException,
1180 js_e.ValidationError,
1181 vimconn.VimConnException,
1182 ) as e:
tiernoae4a8d12016-07-08 12:30:39 +02001183 self.logger.error("Exception getting vm status: %s", str(e))
sousaedu80135b92021-02-17 15:05:18 +01001184 vm["status"] = "VIM_ERROR"
1185 vm["error_msg"] = str(e)
tiernoae4a8d12016-07-08 12:30:39 +02001186 vm_dict[vm_id] = vm
1187 return vm_dict
tierno7edb6752016-03-21 17:37:52 +01001188
tiernoae4a8d12016-07-08 12:30:39 +02001189 def refresh_nets_status(self, net_list):
sousaedu80135b92021-02-17 15:05:18 +01001190 """Get the status of the networks
1191 Params: the list of network identifiers
1192 Returns a dictionary with:
1193 net_id: #VIM id of this network
1194 status: #Mandatory. Text with one of:
1195 # DELETED (not found at vim)
1196 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1197 # OTHER (Vim reported other status not understood)
1198 # ERROR (VIM indicates an ERROR status)
1199 # ACTIVE, INACTIVE, DOWN (admin down),
1200 # BUILD (on building process)
1201 #
1202 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1203 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
tiernoae4a8d12016-07-08 12:30:39 +02001204
sousaedu80135b92021-02-17 15:05:18 +01001205 """
tierno392f2852016-05-13 12:28:55 +02001206 try:
1207 self._get_my_tenant()
tiernoae4a8d12016-07-08 12:30:39 +02001208 except requests.exceptions.RequestException as e:
1209 self._format_request_exception(e)
sousaedu80135b92021-02-17 15:05:18 +01001210
1211 net_dict = {}
tiernoae4a8d12016-07-08 12:30:39 +02001212 for net_id in net_list:
1213 net = {}
sousaedu80135b92021-02-17 15:05:18 +01001214 # print "VIMConnector refresh_tenant_vms_and_nets:
1215 # Getting tenant network from VIM (tenant: " + str(self.tenant) + "): "
tierno7edb6752016-03-21 17:37:52 +01001216 try:
tiernoae4a8d12016-07-08 12:30:39 +02001217 net_vim = self.get_network(net_id)
sousaedu80135b92021-02-17 15:05:18 +01001218 if net_vim["status"] in netStatus2manoFormat:
1219 net["status"] = netStatus2manoFormat[net_vim["status"]]
tierno7edb6752016-03-21 17:37:52 +01001220 else:
tiernoae4a8d12016-07-08 12:30:39 +02001221 net["status"] = "OTHER"
sousaedu80135b92021-02-17 15:05:18 +01001222 net["error_msg"] = "VIM status reported " + net_vim["status"]
1223
1224 if net["status"] == "ACTIVE" and not net_vim["admin_state_up"]:
tiernoae4a8d12016-07-08 12:30:39 +02001225 net["status"] = "DOWN"
sousaedu80135b92021-02-17 15:05:18 +01001226 if net_vim.get("last_error"):
1227 net["error_msg"] = net_vim["last_error"]
tiernoae4a8d12016-07-08 12:30:39 +02001228 net["vim_info"] = yaml.safe_dump(net_vim)
tierno72774862020-05-04 11:44:15 +00001229 except vimconn.VimConnNotFoundException as e:
tiernoae4a8d12016-07-08 12:30:39 +02001230 self.logger.error("Exception getting net status: %s", str(e))
sousaedu80135b92021-02-17 15:05:18 +01001231 net["status"] = "DELETED"
1232 net["error_msg"] = str(e)
1233 except (
1234 requests.exceptions.RequestException,
1235 js_e.ValidationError,
1236 vimconn.VimConnException,
1237 ) as e:
tiernoae4a8d12016-07-08 12:30:39 +02001238 self.logger.error("Exception getting net status: %s", str(e))
sousaedu80135b92021-02-17 15:05:18 +01001239 net["status"] = "VIM_ERROR"
1240 net["error_msg"] = str(e)
tiernoae4a8d12016-07-08 12:30:39 +02001241 net_dict[net_id] = net
1242 return net_dict
sousaedu80135b92021-02-17 15:05:18 +01001243
tierno98e909c2017-10-14 13:27:03 +02001244 def action_vminstance(self, vm_id, action_dict, created_items={}):
sousaedu80135b92021-02-17 15:05:18 +01001245 """Send and action over a VM instance from VIM"""
1246 """Returns the status"""
tierno392f2852016-05-13 12:28:55 +02001247 try:
1248 self._get_my_tenant()
tierno7edb6752016-03-21 17:37:52 +01001249 if "console" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01001250 raise vimconn.VimConnException(
1251 "getting console is not available at openvim",
1252 http_code=vimconn.HTTP_Service_Unavailable,
1253 )
1254 url = self.url + "/" + self.tenant + "/servers/" + vm_id + "/action"
tiernoae4a8d12016-07-08 12:30:39 +02001255 self.logger.info("Action over VM instance POST %s", url)
sousaedu80135b92021-02-17 15:05:18 +01001256 vim_response = requests.post(
1257 url, headers=self.headers_req, data=json.dumps(action_dict)
1258 )
tiernoae4a8d12016-07-08 12:30:39 +02001259 self._check_http_request_response(vim_response)
tierno98e909c2017-10-14 13:27:03 +02001260 return None
tiernoae4a8d12016-07-08 12:30:39 +02001261 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
1262 self._format_request_exception(e)
tierno7edb6752016-03-21 17:37:52 +01001263
sousaedu80135b92021-02-17 15:05:18 +01001264 # NOT USED METHODS in current version
1265
tierno7edb6752016-03-21 17:37:52 +01001266 def host_vim2gui(self, host, server_dict):
sousaedu80135b92021-02-17 15:05:18 +01001267 """Transform host dictionary from VIM format to GUI format,
tierno7edb6752016-03-21 17:37:52 +01001268 and append to the server_dict
sousaedu80135b92021-02-17 15:05:18 +01001269 """
1270 if type(server_dict) is not dict:
1271 print(
1272 "vimconnector.host_vim2gui() ERROR, param server_dict must be a dictionary"
1273 )
tierno7edb6752016-03-21 17:37:52 +01001274 return
sousaedu80135b92021-02-17 15:05:18 +01001275 RAD = {}
1276 occupation = {}
1277 for numa in host["host"]["numas"]:
1278 RAD_item = {}
1279 occupation_item = {}
1280 # memory
1281 RAD_item["memory"] = {
1282 "size": str(numa["memory"]) + "GB",
1283 "eligible": str(numa["hugepages"]) + "GB",
1284 }
1285 occupation_item["memory"] = str(numa["hugepages_consumed"]) + "GB"
1286 # cpus
1287 RAD_item["cpus"] = {}
1288 RAD_item["cpus"]["cores"] = []
1289 RAD_item["cpus"]["eligible_cores"] = []
1290 occupation_item["cores"] = []
1291 for _ in range(0, len(numa["cores"]) // 2):
1292 RAD_item["cpus"]["cores"].append([])
1293 for core in numa["cores"]:
1294 RAD_item["cpus"]["cores"][core["core_id"]].append(core["thread_id"])
1295 if "status" not in core:
1296 RAD_item["cpus"]["eligible_cores"].append(core["thread_id"])
1297 if "instance_id" in core:
1298 occupation_item["cores"].append(core["thread_id"])
1299 # ports
1300 RAD_item["ports"] = {}
1301 occupation_item["ports"] = {}
1302 for iface in numa["interfaces"]:
1303 RAD_item["ports"][iface["pci"]] = "speed:" + str(iface["Mbps"]) + "M"
1304 occupation_item["ports"][iface["pci"]] = {
1305 "occupied": str(100 * iface["Mbps_consumed"] // iface["Mbps"]) + "%"
1306 }
1307
1308 RAD[numa["numa_socket"]] = RAD_item
1309 occupation[numa["numa_socket"]] = occupation_item
1310 server_dict[host["host"]["name"]] = {"RAD": RAD, "occupation": occupation}
tierno7edb6752016-03-21 17:37:52 +01001311
1312 def get_hosts_info(self):
sousaedu80135b92021-02-17 15:05:18 +01001313 """Get the information of deployed hosts
1314 Returns the hosts content"""
1315 # obtain hosts list
1316 url = self.url + "/hosts"
tierno7edb6752016-03-21 17:37:52 +01001317 try:
1318 vim_response = requests.get(url)
venkatamahesh6ecca182017-01-27 23:04:40 +05301319 except requests.exceptions.RequestException as e:
sousaedu80135b92021-02-17 15:05:18 +01001320 print("get_hosts_info Exception: ", e.args)
tierno7edb6752016-03-21 17:37:52 +01001321 return -vimconn.HTTP_Not_Found, str(e.args[0])
sousaedu80135b92021-02-17 15:05:18 +01001322 print(
1323 "vim get", url, "response:", vim_response.status_code, vim_response.json()
1324 )
1325 # print vim_response.status_code
1326 # print json.dumps(vim_response.json(), indent=4)
tierno7edb6752016-03-21 17:37:52 +01001327 if vim_response.status_code != 200:
tierno7d782ef2019-10-04 12:56:31 +00001328 # TODO: get error
sousaedu80135b92021-02-17 15:05:18 +01001329 print(
1330 "vimconnector.get_hosts_info error getting host list {} {}".format(
1331 vim_response.status_code, vim_response.json()
1332 )
1333 )
tierno7edb6752016-03-21 17:37:52 +01001334 return -vim_response.status_code, "Error getting host list"
sousaedu80135b92021-02-17 15:05:18 +01001335
1336 res, hosts = self._format_in(vim_response, get_hosts_response_schema)
1337
1338 if not res:
1339 print(
1340 "vimconnector.get_hosts_info error parsing GET HOSTS vim response",
1341 hosts,
1342 )
tierno7edb6752016-03-21 17:37:52 +01001343 return vimconn.HTTP_Internal_Server_Error, hosts
sousaedu80135b92021-02-17 15:05:18 +01001344 # obtain hosts details
1345 hosts_dict = {}
1346 for host in hosts["hosts"]:
1347 url = self.url + "/hosts/" + host["id"]
tierno7edb6752016-03-21 17:37:52 +01001348 try:
1349 vim_response = requests.get(url)
venkatamahesh6ecca182017-01-27 23:04:40 +05301350 except requests.exceptions.RequestException as e:
sousaedu80135b92021-02-17 15:05:18 +01001351 print("get_hosts_info Exception: ", e.args)
tierno7edb6752016-03-21 17:37:52 +01001352 return -vimconn.HTTP_Not_Found, str(e.args[0])
sousaedu80135b92021-02-17 15:05:18 +01001353 print(
1354 "vim get",
1355 url,
1356 "response:",
1357 vim_response.status_code,
1358 vim_response.json(),
1359 )
tierno7edb6752016-03-21 17:37:52 +01001360 if vim_response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01001361 print(
1362 "vimconnector.get_hosts_info error getting detailed host {} {}".format(
1363 vim_response.status_code, vim_response.json()
1364 )
1365 )
tierno7edb6752016-03-21 17:37:52 +01001366 continue
sousaedu80135b92021-02-17 15:05:18 +01001367 res, host_detail = self._format_in(
1368 vim_response, get_host_detail_response_schema
1369 )
1370 if not res:
1371 print(
1372 "vimconnector.get_hosts_info error parsing GET HOSTS/{} vim response {}".format(
1373 host["id"], host_detail
1374 ),
1375 )
tierno7edb6752016-03-21 17:37:52 +01001376 continue
sousaedu80135b92021-02-17 15:05:18 +01001377 # print 'host id '+host['id'], json.dumps(host_detail, indent=4)
tierno7edb6752016-03-21 17:37:52 +01001378 self.host_vim2gui(host_detail, hosts_dict)
1379 return 200, hosts_dict
1380
1381 def get_hosts(self, vim_tenant):
sousaedu80135b92021-02-17 15:05:18 +01001382 """Get the hosts and deployed instances
1383 Returns the hosts content"""
1384 # obtain hosts list
1385 url = self.url + "/hosts"
tierno7edb6752016-03-21 17:37:52 +01001386 try:
1387 vim_response = requests.get(url)
venkatamahesh6ecca182017-01-27 23:04:40 +05301388 except requests.exceptions.RequestException as e:
tierno7d782ef2019-10-04 12:56:31 +00001389 print("get_hosts Exception: ", e.args)
tierno7edb6752016-03-21 17:37:52 +01001390 return -vimconn.HTTP_Not_Found, str(e.args[0])
sousaedu80135b92021-02-17 15:05:18 +01001391 print(
1392 "vim get", url, "response:", vim_response.status_code, vim_response.json()
1393 )
1394 # print vim_response.status_code
1395 # print json.dumps(vim_response.json(), indent=4)
tierno7edb6752016-03-21 17:37:52 +01001396 if vim_response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01001397 # TODO: get error
1398 print(
1399 "vimconnector.get_hosts error getting host list {} {}".format(
1400 vim_response.status_code, vim_response.json()
1401 )
1402 )
tierno7edb6752016-03-21 17:37:52 +01001403 return -vim_response.status_code, "Error getting host list"
sousaedu80135b92021-02-17 15:05:18 +01001404
1405 res, hosts = self._format_in(vim_response, get_hosts_response_schema)
1406
1407 if not res:
tierno7d782ef2019-10-04 12:56:31 +00001408 print("vimconnector.get_host error parsing GET HOSTS vim response", hosts)
tierno7edb6752016-03-21 17:37:52 +01001409 return vimconn.HTTP_Internal_Server_Error, hosts
sousaedu80135b92021-02-17 15:05:18 +01001410 # obtain instances from hosts
1411 for host in hosts["hosts"]:
1412 url = self.url + "/" + vim_tenant + "/servers?hostId=" + host["id"]
tierno7edb6752016-03-21 17:37:52 +01001413 try:
1414 vim_response = requests.get(url)
venkatamahesh6ecca182017-01-27 23:04:40 +05301415 except requests.exceptions.RequestException as e:
tierno7d782ef2019-10-04 12:56:31 +00001416 print("get_hosts Exception: ", e.args)
tierno7edb6752016-03-21 17:37:52 +01001417 return -vimconn.HTTP_Not_Found, str(e.args[0])
sousaedu80135b92021-02-17 15:05:18 +01001418 print(
1419 "vim get",
1420 url,
1421 "response:",
1422 vim_response.status_code,
1423 vim_response.json(),
1424 )
tierno7edb6752016-03-21 17:37:52 +01001425 if vim_response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01001426 print(
1427 "vimconnector.get_hosts error getting instances at host {} {}".format(
1428 vim_response.status_code, vim_response.json()
1429 )
1430 )
tierno7edb6752016-03-21 17:37:52 +01001431 continue
sousaedu80135b92021-02-17 15:05:18 +01001432 res, servers = self._format_in(vim_response, get_server_response_schema)
1433 if not res:
1434 print(
1435 "vimconnector.get_host error parsing GET SERVERS/{} vim response {}".format(
1436 host["id"], servers
1437 ),
1438 )
tierno7edb6752016-03-21 17:37:52 +01001439 continue
sousaedu80135b92021-02-17 15:05:18 +01001440 # print 'host id '+host['id'], json.dumps(host_detail, indent=4)
1441 host["instances"] = servers["servers"]
1442 return 200, hosts["hosts"]
tierno7edb6752016-03-21 17:37:52 +01001443
1444 def get_processor_rankings(self):
sousaedu80135b92021-02-17 15:05:18 +01001445 """Get the processor rankings in the VIM database"""
1446 url = self.url + "/processor_ranking"
tierno7edb6752016-03-21 17:37:52 +01001447 try:
1448 vim_response = requests.get(url)
venkatamahesh6ecca182017-01-27 23:04:40 +05301449 except requests.exceptions.RequestException as e:
tierno7d782ef2019-10-04 12:56:31 +00001450 print("get_processor_rankings Exception: ", e.args)
tierno7edb6752016-03-21 17:37:52 +01001451 return -vimconn.HTTP_Not_Found, str(e.args[0])
sousaedu80135b92021-02-17 15:05:18 +01001452 print(
1453 "vim get", url, "response:", vim_response.status_code, vim_response.json()
1454 )
1455 # print vim_response.status_code
1456 # print json.dumps(vim_response.json(), indent=4)
tierno7edb6752016-03-21 17:37:52 +01001457 if vim_response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01001458 # TODO: get error
1459 print(
1460 "vimconnector.get_processor_rankings error getting processor rankings {} {}".format(
1461 vim_response.status_code, vim_response.json()
1462 )
1463 )
tierno7edb6752016-03-21 17:37:52 +01001464 return -vim_response.status_code, "Error getting processor rankings"
sousaedu80135b92021-02-17 15:05:18 +01001465
1466 res, rankings = self._format_in(
1467 vim_response, get_processor_rankings_response_schema
1468 )
1469 return res, rankings["rankings"]
1470
tiernoae4a8d12016-07-08 12:30:39 +02001471 def new_host(self, host_data):
sousaedu80135b92021-02-17 15:05:18 +01001472 """Adds a new host to VIM"""
1473 """Returns status code of the VIM response"""
tiernoae4a8d12016-07-08 12:30:39 +02001474 payload_req = host_data
tierno392f2852016-05-13 12:28:55 +02001475 try:
sousaedu80135b92021-02-17 15:05:18 +01001476 url = self.url_admin + "/hosts"
tiernoae4a8d12016-07-08 12:30:39 +02001477 self.logger.info("Adding a new host POST %s", url)
sousaedu80135b92021-02-17 15:05:18 +01001478 vim_response = requests.post(
1479 url, headers=self.headers_req, data=payload_req
1480 )
tiernoae4a8d12016-07-08 12:30:39 +02001481 self._check_http_request_response(vim_response)
1482 self.logger.debug(vim_response.text)
sousaedu80135b92021-02-17 15:05:18 +01001483 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +02001484 response = vim_response.json()
1485 js_v(response, new_host_response_schema)
1486 r = self._remove_extra_items(response, new_host_response_schema)
sousaedu80135b92021-02-17 15:05:18 +01001487 if r is not None:
tiernoae4a8d12016-07-08 12:30:39 +02001488 self.logger.warn("Warning: remove extra items %s", str(r))
sousaedu80135b92021-02-17 15:05:18 +01001489 host_id = response["host"]["id"]
tiernoae4a8d12016-07-08 12:30:39 +02001490 return host_id
1491 except (requests.exceptions.RequestException, js_e.ValidationError) as e:
1492 self._format_request_exception(e)
sousaedu80135b92021-02-17 15:05:18 +01001493
tiernoae4a8d12016-07-08 12:30:39 +02001494 def new_external_port(self, port_data):
sousaedu80135b92021-02-17 15:05:18 +01001495 """Adds a external port to VIM"""
1496 """Returns the port identifier"""
1497 # TODO change to logging exception code policies
1498 print("VIMConnector: Adding a new external port")
tiernoae4a8d12016-07-08 12:30:39 +02001499 payload_req = port_data
tierno7edb6752016-03-21 17:37:52 +01001500 try:
sousaedu80135b92021-02-17 15:05:18 +01001501 vim_response = requests.post(
1502 self.url_admin + "/ports", headers=self.headers_req, data=payload_req
1503 )
venkatamahesh6ecca182017-01-27 23:04:40 +05301504 except requests.exceptions.RequestException as e:
tiernoae4a8d12016-07-08 12:30:39 +02001505 self.logger.error("new_external_port Exception: ", str(e))
tierno7edb6752016-03-21 17:37:52 +01001506 return -vimconn.HTTP_Not_Found, str(e.args[0])
sousaedu80135b92021-02-17 15:05:18 +01001507 print(vim_response)
1508 # print vim_response.status_code
tiernoae4a8d12016-07-08 12:30:39 +02001509 if vim_response.status_code == 200:
sousaedu80135b92021-02-17 15:05:18 +01001510 # print vim_response.json()
1511 # print json.dumps(vim_response.json(), indent=4)
tiernoae4a8d12016-07-08 12:30:39 +02001512 res, http_content = self._format_in(vim_response, new_port_response_schema)
sousaedu80135b92021-02-17 15:05:18 +01001513 # print http_content
tiernoae4a8d12016-07-08 12:30:39 +02001514 if res:
1515 r = self._remove_extra_items(http_content, new_port_response_schema)
sousaedu80135b92021-02-17 15:05:18 +01001516 if r is not None:
1517 print("Warning: remove extra items ", r)
1518 # print http_content
1519 port_id = http_content["port"]["id"]
1520 print("Port id: ", port_id)
1521 return vim_response.status_code, port_id
1522 else:
1523 return -vimconn.HTTP_Bad_Request, http_content
tiernoae4a8d12016-07-08 12:30:39 +02001524 else:
sousaedu80135b92021-02-17 15:05:18 +01001525 # print vim_response.text
tiernoae4a8d12016-07-08 12:30:39 +02001526 jsonerror = self._format_jsonerror(vim_response)
tierno7d782ef2019-10-04 12:56:31 +00001527 text = 'Error in VIM "{}": not possible to add new external port. HTTP Response: {}. Error: {}'.format(
sousaedu80135b92021-02-17 15:05:18 +01001528 self.url_admin, vim_response.status_code, jsonerror
1529 )
1530 # print text
1531 return -vim_response.status_code, text
1532
1533 def new_external_network(self, net_name, net_type):
1534 """Adds a external network to VIM (shared)"""
1535 """Returns the network identifier"""
1536 # TODO change to logging exception code policies
1537 print(
1538 "VIMConnector: Adding external shared network to VIM (type "
1539 + net_type
1540 + "): "
1541 + net_name
1542 )
1543
1544 payload_req = (
1545 '{"network":{"name": "'
1546 + net_name
1547 + '","shared":true,"type": "'
1548 + net_type
1549 + '"}}'
1550 )
tiernoae4a8d12016-07-08 12:30:39 +02001551 try:
sousaedu80135b92021-02-17 15:05:18 +01001552 vim_response = requests.post(
1553 self.url + "/networks", headers=self.headers_req, data=payload_req
1554 )
venkatamahesh6ecca182017-01-27 23:04:40 +05301555 except requests.exceptions.RequestException as e:
sousaedu80135b92021-02-17 15:05:18 +01001556 self.logger.error("new_external_network Exception: ", e.args)
tiernoae4a8d12016-07-08 12:30:39 +02001557 return -vimconn.HTTP_Not_Found, str(e.args[0])
tierno7d782ef2019-10-04 12:56:31 +00001558 print(vim_response)
sousaedu80135b92021-02-17 15:05:18 +01001559 # print vim_response.status_code
tiernoae4a8d12016-07-08 12:30:39 +02001560 if vim_response.status_code == 200:
sousaedu80135b92021-02-17 15:05:18 +01001561 # print vim_response.json()
1562 # print json.dumps(vim_response.json(), indent=4)
1563 res, http_content = self._format_in(
1564 vim_response, new_network_response_schema
1565 )
1566 # print http_content
tiernoae4a8d12016-07-08 12:30:39 +02001567 if res:
1568 r = self._remove_extra_items(http_content, new_network_response_schema)
sousaedu80135b92021-02-17 15:05:18 +01001569 if r is not None:
1570 print("Warning: remove extra items ", r)
1571 # print http_content
1572 network_id = http_content["network"]["id"]
1573 print("Network id: ", network_id)
1574 return vim_response.status_code, network_id
1575 else:
1576 return -vimconn.HTTP_Bad_Request, http_content
tiernoae4a8d12016-07-08 12:30:39 +02001577 else:
sousaedu80135b92021-02-17 15:05:18 +01001578 # print vim_response.text
tiernoae4a8d12016-07-08 12:30:39 +02001579 jsonerror = self._format_jsonerror(vim_response)
tierno7d782ef2019-10-04 12:56:31 +00001580 text = 'Error in VIM "{}": not possible to add new external network. HTTP Response: {}. Error: {}'.format(
sousaedu80135b92021-02-17 15:05:18 +01001581 self.url, vim_response.status_code, jsonerror
1582 )
1583 # print text
1584 return -vim_response.status_code, text
1585
tiernoae4a8d12016-07-08 12:30:39 +02001586 def connect_port_network(self, port_id, network_id, admin=False):
sousaedu80135b92021-02-17 15:05:18 +01001587 """Connects a external port to a network"""
1588 """Returns status code of the VIM response"""
1589 # TODO change to logging exception code policies
tierno7d782ef2019-10-04 12:56:31 +00001590 print("VIMConnector: Connecting external port to network")
sousaedu80135b92021-02-17 15:05:18 +01001591
tiernoae4a8d12016-07-08 12:30:39 +02001592 payload_req = '{"port":{"network_id":"' + network_id + '"}}'
1593 if admin:
sousaedu80135b92021-02-17 15:05:18 +01001594 if self.url_admin is None:
1595 return (
1596 -vimconn.HTTP_Unauthorized,
1597 "datacenter cannot contain admin URL",
1598 )
1599 url = self.url_admin
tiernoae4a8d12016-07-08 12:30:39 +02001600 else:
sousaedu80135b92021-02-17 15:05:18 +01001601 url = self.url
tiernoae4a8d12016-07-08 12:30:39 +02001602 try:
sousaedu80135b92021-02-17 15:05:18 +01001603 vim_response = requests.put(
1604 url + "/ports/" + port_id, headers=self.headers_req, data=payload_req
1605 )
venkatamahesh6ecca182017-01-27 23:04:40 +05301606 except requests.exceptions.RequestException as e:
tierno7d782ef2019-10-04 12:56:31 +00001607 print("connect_port_network Exception: ", e.args)
tiernoae4a8d12016-07-08 12:30:39 +02001608 return -vimconn.HTTP_Not_Found, str(e.args[0])
tierno7d782ef2019-10-04 12:56:31 +00001609 print(vim_response)
sousaedu80135b92021-02-17 15:05:18 +01001610 # print vim_response.status_code
tiernoae4a8d12016-07-08 12:30:39 +02001611 if vim_response.status_code == 200:
sousaedu80135b92021-02-17 15:05:18 +01001612 # print vim_response.json()
1613 # print json.dumps(vim_response.json(), indent=4)
1614 res, http_content = self._format_in(vim_response, new_port_response_schema)
1615 # print http_content
tiernoae4a8d12016-07-08 12:30:39 +02001616 if res:
1617 r = self._remove_extra_items(http_content, new_port_response_schema)
sousaedu80135b92021-02-17 15:05:18 +01001618 if r is not None:
1619 print("Warning: remove extra items ", r)
1620 # print http_content
1621 port_id = http_content["port"]["id"]
1622 print("Port id: ", port_id)
1623 return vim_response.status_code, port_id
1624 else:
1625 return -vimconn.HTTP_Bad_Request, http_content
tiernoae4a8d12016-07-08 12:30:39 +02001626 else:
tierno7d782ef2019-10-04 12:56:31 +00001627 print(vim_response.text)
tiernoae4a8d12016-07-08 12:30:39 +02001628 jsonerror = self._format_jsonerror(vim_response)
sousaedu80135b92021-02-17 15:05:18 +01001629 text = (
1630 'Error in VIM "{}": not possible to connect external port to network. HTTP Response: {}.'
1631 " Error: {}".format(self.url_admin, vim_response.status_code, jsonerror)
1632 )
tierno7d782ef2019-10-04 12:56:31 +00001633 print(text)
sousaedu80135b92021-02-17 15:05:18 +01001634 return -vim_response.status_code, text