mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-22 13:34:04 +03:00
added remove duplicates to open stack
This commit is contained in:
parent
43d0f3b4d4
commit
4fea6e6a3e
@ -120,6 +120,17 @@ class TestOpenStackClient(UDSTransactionTestCase):
|
||||
msg='Timeout waiting for snapshot to be available',
|
||||
)
|
||||
|
||||
def wait_for_server(
|
||||
self,
|
||||
server: openstack_types.ServerInfo,
|
||||
power_state: openstack_types.PowerState = openstack_types.PowerState.RUNNING,
|
||||
) -> None:
|
||||
helpers.waiter(
|
||||
lambda: self.oclient.get_server_info(server.id, force=True).power_state == power_state,
|
||||
timeout=30,
|
||||
msg='Timeout waiting for server to be running',
|
||||
)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def create_test_volume(self) -> typing.Iterator[openstack_types.VolumeInfo]:
|
||||
volume = self.oclient.t_create_volume(
|
||||
@ -164,7 +175,11 @@ class TestOpenStackClient(UDSTransactionTestCase):
|
||||
)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def create_test_server(self) -> typing.Iterator[openstack_types.ServerInfo]:
|
||||
def create_test_server(
|
||||
self,
|
||||
) -> typing.Iterator[
|
||||
tuple[openstack_types.ServerInfo, openstack_types.VolumeInfo, openstack_types.SnapshotInfo]
|
||||
]:
|
||||
with self.create_test_volume() as volume:
|
||||
with self.create_test_snapshot(volume) as snapshot:
|
||||
server = self.oclient.create_server_from_snapshot(
|
||||
@ -177,14 +192,10 @@ class TestOpenStackClient(UDSTransactionTestCase):
|
||||
)
|
||||
try:
|
||||
# Wait for server to be running
|
||||
helpers.waiter(
|
||||
lambda: self.oclient.get_server_info(server.id, force=True).power_state.is_running(),
|
||||
timeout=30,
|
||||
msg='Timeout waiting for server to be running',
|
||||
)
|
||||
self.wait_for_server(server)
|
||||
# Reget server info to complete all data
|
||||
server = self.oclient.get_server_info(server.id, force=True)
|
||||
yield server
|
||||
yield server, volume, snapshot
|
||||
finally:
|
||||
self.oclient.delete_server(server.id)
|
||||
|
||||
@ -199,8 +210,8 @@ class TestOpenStackClient(UDSTransactionTestCase):
|
||||
self.assertIn(self._regionid, [r.id for r in regions])
|
||||
|
||||
def test_list_servers(self) -> None:
|
||||
with self.create_test_server() as server1:
|
||||
with self.create_test_server() as server2:
|
||||
with self.create_test_server() as (server1, _, _):
|
||||
with self.create_test_server() as (server2, _, _):
|
||||
servers = self.oclient.list_servers(force=True)
|
||||
self.assertGreaterEqual(len(servers), 2)
|
||||
self.assertIn(
|
||||
@ -262,7 +273,7 @@ class TestOpenStackClient(UDSTransactionTestCase):
|
||||
self.assertIn(self._security_group_name, [sg.name for sg in security_groups])
|
||||
|
||||
def test_get_server_info(self) -> None:
|
||||
with self.create_test_server() as server:
|
||||
with self.create_test_server() as (server, _, _):
|
||||
server_info = self.oclient.get_server_info(server.id)
|
||||
self.assertEqual(server.id, server_info.id)
|
||||
self.assertEqual(server.name, server_info.name)
|
||||
@ -303,7 +314,7 @@ class TestOpenStackClient(UDSTransactionTestCase):
|
||||
self.oclient.create_snapshot(volume_id='non-existing-volume', name='non-existing-snapshot')
|
||||
|
||||
def test_create_server_from_snapshot(self) -> None:
|
||||
with self.create_test_server() as server:
|
||||
with self.create_test_server() as (server, _, _):
|
||||
self.assertIsNotNone(server.id)
|
||||
|
||||
# Trying to create a server from a non existing snapshot should raise an exceptions.NotFoundException
|
||||
@ -330,23 +341,16 @@ class TestOpenStackClient(UDSTransactionTestCase):
|
||||
self.oclient.delete_snapshot('non-existing-snapshot')
|
||||
|
||||
def test_operations_server(self) -> None:
|
||||
with self.create_test_server() as server:
|
||||
with self.create_test_server() as (server, _, _):
|
||||
# Server is already running, first stop it
|
||||
self.oclient.stop_server(server.id)
|
||||
helpers.waiter(
|
||||
lambda: self.oclient.get_server_info(server.id, force=True).power_state.is_stopped(),
|
||||
timeout=30,
|
||||
msg='Timeout waiting for server to be stopped',
|
||||
)
|
||||
self.wait_for_server(server, openstack_types.PowerState.SHUTDOWN)
|
||||
|
||||
self.oclient.start_server(server.id)
|
||||
helpers.waiter(
|
||||
lambda: self.oclient.get_server_info(server.id, force=True).power_state.is_running(),
|
||||
timeout=30,
|
||||
msg='Timeout waiting for server to be running',
|
||||
)
|
||||
self.wait_for_server(server)
|
||||
|
||||
self.oclient.reset_server(server.id)
|
||||
# Here we need to wait for the server to be active again
|
||||
helpers.waiter(
|
||||
lambda: self.oclient.get_server_info(server.id, force=True).status.is_active(),
|
||||
timeout=30,
|
||||
@ -355,19 +359,11 @@ class TestOpenStackClient(UDSTransactionTestCase):
|
||||
|
||||
# Suspend
|
||||
self.oclient.suspend_server(server.id)
|
||||
helpers.waiter(
|
||||
lambda: self.oclient.get_server_info(server.id, force=True).power_state.is_suspended(),
|
||||
timeout=30,
|
||||
msg='Timeout waiting for server to be suspended',
|
||||
)
|
||||
self.wait_for_server(server, openstack_types.PowerState.SUSPENDED)
|
||||
|
||||
# Resume
|
||||
self.oclient.resume_server(server.id)
|
||||
helpers.waiter(
|
||||
lambda: self.oclient.get_server_info(server.id, force=True).power_state.is_running(),
|
||||
timeout=30,
|
||||
msg='Timeout waiting for server to be running',
|
||||
)
|
||||
self.wait_for_server(server)
|
||||
|
||||
# Reboot
|
||||
self.oclient.reboot_server(server.id)
|
||||
@ -399,6 +395,25 @@ class TestOpenStackClient(UDSTransactionTestCase):
|
||||
|
||||
def test_test_connection(self) -> None:
|
||||
self.assertTrue(self.oclient.test_connection())
|
||||
|
||||
|
||||
def test_is_available(self) -> None:
|
||||
self.assertTrue(self.oclient.is_available())
|
||||
self.assertTrue(self.oclient.is_available())
|
||||
|
||||
# Some useful tests
|
||||
def test_duplicated_server_name(self) -> None:
|
||||
with self.create_test_server() as (server, _volume, snapshot):
|
||||
res = self.oclient.create_server_from_snapshot(
|
||||
snapshot_id=snapshot.id,
|
||||
name=server.name,
|
||||
flavor_id=self._flavorid,
|
||||
network_id=self._networkid,
|
||||
security_groups_names=[],
|
||||
availability_zone=self._availability_zone_id,
|
||||
)
|
||||
# Has been created, and no problem at all
|
||||
self.assertIsNotNone(res)
|
||||
|
||||
# Now, delete it
|
||||
# wait for server to be running
|
||||
self.wait_for_server(res)
|
||||
self.oclient.delete_server(res.id)
|
||||
|
@ -77,7 +77,6 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
|
||||
order=102,
|
||||
tab=types.ui.Tab.ADVANCED,
|
||||
)
|
||||
|
||||
maintain_on_error = fields.maintain_on_error_field(
|
||||
order=103,
|
||||
tab=types.ui.Tab.ADVANCED,
|
||||
@ -110,7 +109,7 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
|
||||
"""
|
||||
return name
|
||||
|
||||
# overridable
|
||||
# overridable, but not needed if no remove_duplicates is used
|
||||
def find_duplicates(self, name: str, mac: str) -> collections.abc.Iterable[str]:
|
||||
"""
|
||||
Checks if a machine with the same name or mac exists
|
||||
@ -125,6 +124,8 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
|
||||
|
||||
Note:
|
||||
Maybe we can only check name or mac, or both, depending on the service
|
||||
This method must be be provided if the field remove_duplicates is used
|
||||
If not, will raise a NotImplementedError
|
||||
"""
|
||||
raise NotImplementedError(f'{self.__class__}: find_duplicates must be implemented if remove_duplicates is used!')
|
||||
|
||||
|
@ -519,6 +519,7 @@ class DynamicUserService(services.UserService, autoserializable.AutoSerializable
|
||||
def remove_duplicated_names(self) -> None:
|
||||
name = self.get_vmname()
|
||||
try:
|
||||
retry = False
|
||||
for vmid in self.service().perform_find_duplicates(name, self.get_unique_id()):
|
||||
userservice = self.db_obj()
|
||||
log.log(
|
||||
@ -528,7 +529,12 @@ class DynamicUserService(services.UserService, autoserializable.AutoSerializable
|
||||
types.log.LogSource.SERVICE,
|
||||
)
|
||||
self.service().delete(self, vmid)
|
||||
retry = True
|
||||
if retry:
|
||||
# Retry again in a while if duplicated machines where found, until we remove all of them
|
||||
# Note that this way, can request the deletion of the same machine multiple times
|
||||
# but this is not a problem, as the service will simply ignore the request if the machine is not there
|
||||
# when the deletion is requested
|
||||
self.retry_later()
|
||||
except Exception as e:
|
||||
logger.warning('Locating duplicated machines: %s', e)
|
||||
|
@ -1,11 +1,14 @@
|
||||
from uds.core import exceptions as core_exceptions
|
||||
|
||||
|
||||
class Error(core_exceptions.UDSException):
|
||||
"""
|
||||
Base exception for this module
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class RetryableError(Error):
|
||||
"""
|
||||
Exception that is raised when an error is detected that can be retried
|
||||
@ -31,3 +34,12 @@ class NotFoundError(Error):
|
||||
|
||||
def __init__(self, message: str):
|
||||
super().__init__(message)
|
||||
|
||||
|
||||
class AlreadyExistsError(Error):
|
||||
"""
|
||||
Exception that is raised when an object already exists
|
||||
"""
|
||||
|
||||
def __init__(self, message: str):
|
||||
super().__init__(message)
|
||||
|
@ -198,7 +198,7 @@ def get_certificates_from_field(
|
||||
|
||||
# Timeout
|
||||
def timeout_field(
|
||||
default: int = 3,
|
||||
default: int = 5,
|
||||
order: int = 90,
|
||||
tab: 'types.ui.Tab|str|None' = types.ui.Tab.ADVANCED,
|
||||
old_field_name: typing.Optional[str] = None,
|
||||
|
@ -31,6 +31,7 @@
|
||||
Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import logging
|
||||
import collections.abc
|
||||
import typing
|
||||
|
||||
from django.utils.translation import gettext_noop as _
|
||||
@ -178,6 +179,7 @@ class OpenStackLiveService(DynamicService):
|
||||
|
||||
maintain_on_error = DynamicService.maintain_on_error
|
||||
try_soft_shutdown = DynamicService.try_soft_shutdown
|
||||
remove_duplicates = DynamicService.remove_duplicates
|
||||
|
||||
prov_uuid = gui.HiddenField()
|
||||
|
||||
@ -233,6 +235,12 @@ class OpenStackLiveService(DynamicService):
|
||||
def sanitized_name(self, name: str) -> str:
|
||||
return self.provider().sanitized_name(name)
|
||||
|
||||
def find_duplicates(self, name: str, mac: str) -> collections.abc.Iterable[str]:
|
||||
# Only looks for name duplicates, the mac is created by openstack, so it should be unique
|
||||
for i in self.api.list_servers():
|
||||
if i.name == name:
|
||||
yield i.id
|
||||
|
||||
def get_ip(self, caller_instance: typing.Optional['DynamicUserService | DynamicPublication'], vmid: str) -> str:
|
||||
return self.api.get_server_info(vmid).validated().addresses[0].ip
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user