1 # -*- coding: utf-8 -*-
4 # Copyright 2020 Telefonica Investigacion y Desarrollo, S.A.U.
6 # Licensed under the Apache License, Version 2.0 (the "License"); you may
7 # not use this file except in compliance with the License. You may obtain
8 # a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 # License for the specific language governing permissions and limitations
20 Implements a Dummy vim plugin.
23 from copy
import deepcopy
25 from random
import randrange
26 from uuid
import uuid4
28 from osm_ro_plugin
import vimconn
32 __author__
= "Alfonso Tierno"
33 __date__
= "2020-04-20"
36 class VimDummyConnector(vimconn
.VimConnector
):
37 """Dummy vim connector that does nothing
39 vm_ip: ip address to provide at VM creation. For some tests must be a valid reachable VM
40 ssh_key: private ssh key to use for inserting an authorized ssh key
70 self
.logger
= logging
.getLogger("ro.vim.dummy")
73 self
.logger
.setLevel(getattr(logging
, log_level
))
80 "vim_info": "{status: ACTIVE}",
88 "90681b39-dc09-49b7-ba2e-2c00c6b33b76": {
89 "id": "90681b39-dc09-49b7-ba2e-2c00c6b33b76",
91 "checksum": "ee1eca47dc88f4879d8a229cc70a07c6",
93 "83a39656-65db-47dc-af03-b55289115a53": {
96 "checksum": "443b7623e27ecf03dc9e01ee93f67afe",
98 "208314f2-8eb6-4101-965d-fe2ffbaedf3c": {
99 "id": "208314f2-8eb6-4101-965d-fe2ffbaedf3c",
100 "name": "ubuntu18.04",
101 "checksum": "b6fc7b9b91bca32e989e1edbcdeecb95",
103 "c03321f8-4b6e-4045-a309-1b3878bd32c1": {
104 "id": "c03321f8-4b6e-4045-a309-1b3878bd32c1",
105 "name": "ubuntu16.04",
106 "checksum": "8f08442faebad2d4a99fedb22fca11b5",
108 "4f6399a2-3554-457e-916e-ada01f8b950b": {
109 "id": "4f6399a2-3554-457e-916e-ada01f8b950b",
110 "name": "ubuntu1604",
111 "checksum": "8f08442faebad2d4a99fedb22fca11b5",
113 "59ac0b79-5c7d-4e83-b517-4c6c6a8ac1d3": {
114 "id": "59ac0b79-5c7d-4e83-b517-4c6c6a8ac1d3",
115 "name": "hackfest3-mgmt",
116 "checksum": "acec1e5d5ad7be9be7e6342a16bcf66a",
118 "f8818a03-f099-4c18-b1c7-26b1324203c1": {
119 "id": "f8818a03-f099-4c18-b1c7-26b1324203c1",
120 "name": "hackfest-pktgen",
121 "checksum": "f8818a03-f099-4c18-b1c7-26b1324203c1",
131 provider_network_profile
=None,
133 net_id
= str(uuid4())
135 "new network id={}, name={}, net_type={}, ip_profile={}, provider_network_profile={}".format(
136 net_id
, net_name
, net_type
, ip_profile
, provider_network_profile
142 "net_type": net_type
,
145 self
.nets
[net_id
] = net
149 def get_network_list(self
, filter_dict
=None):
152 for net_id
, net
in self
.nets
.items():
153 if filter_dict
and filter_dict
.get("name"):
154 if net
["name"] != filter_dict
.get("name"):
157 if filter_dict
and filter_dict
.get("id"):
158 if net_id
!= filter_dict
.get("id"):
163 # if no network is returned and search by name create a new one
164 if not nets
and filter_dict
and filter_dict
.get("name"):
165 net_id
, net
= self
.new_network(filter_dict
.get("name"), "mgmt")
170 def get_network(self
, net_id
):
171 if net_id
not in self
.nets
:
172 raise vimconn
.VimConnNotFoundException(
173 "network with id {} not found".format(net_id
)
176 return self
.nets
[net_id
]
178 def delete_network(self
, net_id
, created_items
=None):
179 if net_id
not in self
.nets
:
180 raise vimconn
.VimConnNotFoundException(
181 "network with id {} not found".format(net_id
)
185 "delete network id={}, created_items={}".format(net_id
, created_items
)
187 self
.nets
.pop(net_id
)
191 def refresh_nets_status(self
, net_list
):
194 for net_id
in net_list
:
195 if net_id
not in self
.nets
:
196 net
= {"status": "DELETED"}
198 net
= self
.nets
[net_id
].copy()
199 net
["vim_info"] = yaml
.dump(
200 {"status": "ACTIVE", "name": net
["name"]},
201 default_flow_style
=True,
209 def get_flavor(self
, flavor_id
):
210 if flavor_id
not in self
.flavors
:
211 raise vimconn
.VimConnNotFoundException(
212 "flavor with id {} not found".format(flavor_id
)
215 return self
.flavors
[flavor_id
]
217 def new_flavor(self
, flavor_data
):
218 flavor_id
= str(uuid4())
220 "new flavor id={}, flavor_data={}".format(flavor_id
, flavor_data
)
222 flavor
= deepcopy(flavor_data
)
223 flavor
["id"] = flavor_id
225 if "name" not in flavor
:
226 flavor
["name"] = flavor_id
228 self
.flavors
[flavor_id
] = flavor
232 def delete_flavor(self
, flavor_id
):
233 if flavor_id
not in self
.flavors
:
234 raise vimconn
.VimConnNotFoundException(
235 "flavor with id {} not found".format(flavor_id
)
238 self
.logger
.debug("delete flavor id={}".format(flavor_id
))
239 self
.flavors
.pop(flavor_id
)
243 def get_flavor_id_from_data(self
, flavor_dict
):
244 for flavor_id
, flavor_data
in self
.flavors
.items():
245 for k
in ("ram", "vcpus", "disk", "extended"):
246 if flavor_data
.get(k
) != flavor_dict
.get(k
):
251 raise vimconn
.VimConnNotFoundException(
252 "flavor with ram={} cpu={} disk={} {} not found".format(
254 flavor_dict
["vcpus"],
256 "and extended" if flavor_dict
.get("extended") else "",
260 def new_tenant(self
, tenant_name
, tenant_description
):
261 tenant_id
= str(uuid4())
263 "new tenant id={}, description={}".format(tenant_id
, tenant_description
)
267 "description": tenant_description
,
270 self
.tenants
[tenant_id
] = tenant
274 def delete_tenant(self
, tenant_id
):
275 if tenant_id
not in self
.tenants
:
276 raise vimconn
.VimConnNotFoundException(
277 "tenant with id {} not found".format(tenant_id
)
280 self
.tenants
.pop(tenant_id
)
281 self
.logger
.debug("delete tenant id={}".format(tenant_id
))
285 def get_tenant_list(self
, filter_dict
=None):
288 for tenant_id
, tenant
in self
.tenants
.items():
289 if filter_dict
and filter_dict
.get("name"):
290 if tenant
["name"] != filter_dict
.get("name"):
293 if filter_dict
and filter_dict
.get("id"):
294 if tenant_id
!= filter_dict
.get("id"):
297 tenants
.append(tenant
)
301 def new_image(self
, image_dict
):
302 image_id
= str(uuid4())
303 self
.logger
.debug("new image id={}, iamge_dict={}".format(image_id
, image_dict
))
304 image
= deepcopy(image_dict
)
305 image
["id"] = image_id
307 if "name" not in image
:
308 image
["id"] = image_id
310 self
.images
[image_id
] = image
314 def delete_image(self
, image_id
):
315 if image_id
not in self
.images
:
316 raise vimconn
.VimConnNotFoundException(
317 "image with id {} not found".format(image_id
)
320 self
.logger
.debug("delete image id={}".format(image_id
))
321 self
.images
.pop(image_id
)
325 def get_image_list(self
, filter_dict
=None):
327 for image_id
, image
in self
.images
.items():
328 if filter_dict
and filter_dict
.get("name"):
329 if image
["name"] != filter_dict
.get("name"):
332 if filter_dict
and filter_dict
.get("checksum"):
333 if image
["checksum"] != filter_dict
.get("checksum"):
336 if filter_dict
and filter_dict
.get("id"):
337 if image_id
!= filter_dict
.get("id"):
355 availability_zone_index
=None,
356 availability_zone_list
=None,
361 "new vm id={}, name={}, image_id={}, flavor_id={}, net_list={}, cloud_config={}".format(
362 vm_id
, name
, image_id
, flavor_id
, net_list
, cloud_config
366 for iface_index
, iface
in enumerate(net_list
):
367 iface
["vim_id"] = str(iface_index
)
369 "ip_address": iface
.get("ip_address")
370 or self
.config
.get("vm_ip")
372 "mac_address": iface
.get("mac_address")
373 or self
.config
.get("vm_mac")
374 or "00:11:22:33:44:55",
375 "vim_interface_id": str(iface_index
),
376 "vim_net_id": iface
["net_id"],
379 if iface
.get("type") in ("SR-IOV", "PCI-PASSTHROUGH") and self
.config
.get(
382 compute_index
= randrange(len(self
.config
["sdn-port-mapping"]))
383 port_index
= randrange(
384 len(self
.config
["sdn-port-mapping"][compute_index
]["ports"])
386 interface
["compute_node"] = self
.config
["sdn-port-mapping"][
389 interface
["pci"] = self
.config
["sdn-port-mapping"][compute_index
][
393 interfaces
.append(interface
)
399 "description": description
,
400 "interfaces": interfaces
,
401 "image_id": image_id
,
402 "flavor_id": flavor_id
,
405 if image_id
not in self
.images
:
407 "vm create, image_id '{}' not found. Skip".format(image_id
)
410 if flavor_id
not in self
.flavors
:
412 "vm create flavor_id '{}' not found. Skip".format(flavor_id
)
419 def get_vminstance(self
, vm_id
):
420 if vm_id
not in self
.vms
:
421 raise vimconn
.VimConnNotFoundException(
422 "vm with id {} not found".format(vm_id
)
425 return self
.vms
[vm_id
]
427 def delete_vminstance(self
, vm_id
, created_items
=None, volumes_to_hold
=None):
428 if vm_id
not in self
.vms
:
429 raise vimconn
.VimConnNotFoundException(
430 "vm with id {} not found".format(vm_id
)
435 "delete vm id={}, created_items={}".format(vm_id
, created_items
)
440 def refresh_vms_status(self
, vm_list
):
443 for vm_id
in vm_list
:
444 if vm_id
not in self
.vms
:
445 vm
= {"status": "DELETED"}
447 vm
= deepcopy(self
.vms
[vm_id
])
448 vm
["vim_info"] = yaml
.dump(
449 {"status": "ACTIVE", "name": vm
["name"]},
450 default_flow_style
=True,
458 def action_vminstance(self
, vm_id
, action_dict
, created_items
={}):
462 self
, ip_addr
=None, user
=None, key
=None, ro_key
=None, password
=None
464 if self
.config
.get("ssh_key"):
465 ro_key
= self
.config
.get("ssh_key")
467 return super().inject_user_key(
468 ip_addr
=ip_addr
, user
=user
, key
=key
, ro_key
=ro_key
, password
=password