1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-22 13:34:04 +03:00

Some renaming for better significance

This commit is contained in:
Adolfo Gómez García 2024-03-23 23:12:00 +01:00
parent 8f98314c97
commit 9320eb3adf
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
20 changed files with 151 additions and 167 deletions

View File

@ -10,6 +10,7 @@ Author: Adolfo Gómez, dkmaster at dkmon dot com
import abc import abc
import collections.abc import collections.abc
import functools
import logging import logging
import time import time
import typing import typing
@ -20,11 +21,23 @@ from uds.core.types.services import Operation
from uds.core.util import autoserializable from uds.core.util import autoserializable
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from .dynamic_service import DynamicService from .service import DynamicService
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Decorator that tests that _vmid is not empty
# Used by some default methods that require a vmid to work
def must_have_vmid(fnc: typing.Callable[[typing.Any], None]) -> typing.Callable[['DynamicPublication'], None]:
@functools.wraps(fnc)
def wrapper(self: 'DynamicPublication') -> None:
if self._vmid == '':
raise Exception(f'No machine id on {self._name} for {fnc}')
return fnc(self)
return wrapper
class DynamicPublication(services.Publication, autoserializable.AutoSerializable, abc.ABC): class DynamicPublication(services.Publication, autoserializable.AutoSerializable, abc.ABC):
# Very simmilar to DynamicUserService, but with some differences # Very simmilar to DynamicUserService, but with some differences
suggested_delay = 20 # For publications, we can check every 20 seconds suggested_delay = 20 # For publications, we can check every 20 seconds
@ -102,12 +115,6 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
""" """
return True return True
def publish(self) -> types.states.TaskState:
""" """
self._queue = self._publish_queue.copy()
self._debug('publish')
return self._execute_queue()
def _execute_queue(self) -> types.states.TaskState: def _execute_queue(self) -> types.states.TaskState:
self._debug('execute_queue') self._debug('execute_queue')
op = self._current_op() op = self._current_op()
@ -135,6 +142,14 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
logger.exception('Unexpected FixedUserService exception: %s', e) logger.exception('Unexpected FixedUserService exception: %s', e)
return self._error(str(e)) return self._error(str(e))
@typing.final
def publish(self) -> types.states.TaskState:
""" """
self._queue = self._publish_queue.copy()
self._debug('publish')
return self._execute_queue()
@typing.final
def check_state(self) -> types.states.TaskState: def check_state(self) -> types.states.TaskState:
""" """
Check what operation is going on, and acts acordly to it Check what operation is going on, and acts acordly to it
@ -246,6 +261,7 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
""" """
pass pass
@must_have_vmid
def op_start(self) -> None: def op_start(self) -> None:
""" """
This method is called when the service is started This method is called when the service is started
@ -258,6 +274,7 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
""" """
pass pass
@must_have_vmid
def op_stop(self) -> None: def op_stop(self) -> None:
""" """
This method is called for stopping the service This method is called for stopping the service
@ -270,6 +287,7 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
""" """
pass pass
@must_have_vmid
def op_shutdown(self) -> None: def op_shutdown(self) -> None:
""" """
This method is called for shutdown the service This method is called for shutdown the service
@ -282,31 +300,6 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
""" """
pass pass
def op_suspend(self) -> None:
"""
This method is called for suspend the service
"""
# Note that by default suspend is "shutdown" and not "stop" because we
self.service().suspend_machine(self, self._vmid)
def op_suspend_completed(self) -> None:
"""
This method is called when the service suspension is completed
"""
pass
def op_reset(self) -> None:
"""
This method is called when the service is reset
"""
pass
def op_reset_completed(self) -> None:
"""
This method is called when the service reset is completed
"""
self.service().reset_machine(self, self._vmid)
def op_remove(self) -> None: def op_remove(self) -> None:
""" """
This method is called when the service is removed This method is called when the service is removed
@ -320,14 +313,6 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
""" """
pass pass
def op_wait(self) -> None:
"""
This method is called when the service is waiting
Basically, will stop the execution of the queue until something external changes it (i.e. poping from the queue)
Executor does nothing
"""
pass
def op_nop(self) -> None: def op_nop(self) -> None:
""" """
This method is called when the service is doing nothing This method is called when the service is doing nothing
@ -397,24 +382,6 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
""" """
return types.states.TaskState.FINISHED return types.states.TaskState.FINISHED
def op_suspend_checker(self) -> types.states.TaskState:
"""
This method is called to check if the service is suspended
"""
return types.states.TaskState.FINISHED
def op_suspend_completed_checker(self) -> types.states.TaskState:
"""
This method is called to check if the service suspension is completed
"""
return types.states.TaskState.FINISHED
def op_reset_checker(self) -> types.states.TaskState:
"""
This method is called to check if the service is reset
"""
return types.states.TaskState.FINISHED
def op_remove_checker(self) -> types.states.TaskState: def op_remove_checker(self) -> types.states.TaskState:
""" """
This method is called to check if the service is removed This method is called to check if the service is removed
@ -427,12 +394,6 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
""" """
return types.states.TaskState.FINISHED return types.states.TaskState.FINISHED
def op_wait_checker(self) -> types.states.TaskState:
"""
Wait will remain in the same state until something external changes it (i.e. poping from the queue)
"""
return types.states.TaskState.RUNNING
def op_nop_checker(self) -> types.states.TaskState: def op_nop_checker(self) -> types.states.TaskState:
""" """
This method is called to check if the service is doing nothing This method is called to check if the service is doing nothing
@ -446,6 +407,14 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
return types.states.TaskState.FINISHED return types.states.TaskState.FINISHED
# ERROR, FINISH and UNKNOWN are not here, as they are final states not needing to be checked # ERROR, FINISH and UNKNOWN are not here, as they are final states not needing to be checked
# We use same operation type for Publication and UserService. We add "unsupported" to
# cover not defined operations (will raise an exception)
def op_unsupported(self) -> None:
raise Exception('Operation not defined')
def op_unsupported_checker(self) -> types.states.TaskState:
raise Exception('Operation not defined')
@staticmethod @staticmethod
def _op2str(op: Operation) -> str: def _op2str(op: Operation) -> str:
@ -480,11 +449,11 @@ _EXECUTORS: typing.Final[
Operation.STOP_COMPLETED: DynamicPublication.op_stop_completed, Operation.STOP_COMPLETED: DynamicPublication.op_stop_completed,
Operation.SHUTDOWN: DynamicPublication.op_shutdown, Operation.SHUTDOWN: DynamicPublication.op_shutdown,
Operation.SHUTDOWN_COMPLETED: DynamicPublication.op_shutdown_completed, Operation.SHUTDOWN_COMPLETED: DynamicPublication.op_shutdown_completed,
Operation.SUSPEND: DynamicPublication.op_suspend, Operation.SUSPEND: DynamicPublication.op_unsupported,
Operation.SUSPEND_COMPLETED: DynamicPublication.op_suspend_completed, Operation.SUSPEND_COMPLETED: DynamicPublication.op_unsupported,
Operation.REMOVE: DynamicPublication.op_remove, Operation.REMOVE: DynamicPublication.op_remove,
Operation.REMOVE_COMPLETED: DynamicPublication.op_remove_completed, Operation.REMOVE_COMPLETED: DynamicPublication.op_remove_completed,
Operation.WAIT: DynamicPublication.op_wait, Operation.WAIT: DynamicPublication.op_unsupported,
Operation.NOP: DynamicPublication.op_nop, Operation.NOP: DynamicPublication.op_nop,
} }
@ -501,10 +470,10 @@ _CHECKERS: typing.Final[
Operation.STOP_COMPLETED: DynamicPublication.op_stop_completed_checker, Operation.STOP_COMPLETED: DynamicPublication.op_stop_completed_checker,
Operation.SHUTDOWN: DynamicPublication.op_shutdown_checker, Operation.SHUTDOWN: DynamicPublication.op_shutdown_checker,
Operation.SHUTDOWN_COMPLETED: DynamicPublication.op_shutdown_completed_checker, Operation.SHUTDOWN_COMPLETED: DynamicPublication.op_shutdown_completed_checker,
Operation.SUSPEND: DynamicPublication.op_suspend_checker, Operation.SUSPEND: DynamicPublication.op_unsupported_checker,
Operation.SUSPEND_COMPLETED: DynamicPublication.op_suspend_completed_checker, Operation.SUSPEND_COMPLETED: DynamicPublication.op_unsupported_checker,
Operation.REMOVE: DynamicPublication.op_remove_checker, Operation.REMOVE: DynamicPublication.op_remove_checker,
Operation.REMOVE_COMPLETED: DynamicPublication.op_remove_completed_checker, Operation.REMOVE_COMPLETED: DynamicPublication.op_remove_completed_checker,
Operation.WAIT: DynamicPublication.op_wait_checker, Operation.WAIT: DynamicPublication.op_unsupported_checker,
Operation.NOP: DynamicPublication.op_nop_checker, Operation.NOP: DynamicPublication.op_nop_checker,
} }

View File

@ -39,8 +39,8 @@ from uds.core.util import fields, validators
# Not imported at runtime, just for type checking # Not imported at runtime, just for type checking
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from .dynamic_userservice import DynamicUserService from .userservice import DynamicUserService
from .dynamic_publication import DynamicPublication from .publication import DynamicPublication
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -149,7 +149,7 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
@abc.abstractmethod @abc.abstractmethod
def start_machine( def start_machine(
self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str
) -> typing.Any: ) -> None:
""" """
Starts the machine Starts the machine
Can return a task, or None if no task is returned Can return a task, or None if no task is returned
@ -157,7 +157,7 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
... ...
@abc.abstractmethod @abc.abstractmethod
def stop_machine(self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str) -> typing.Any: def stop_machine(self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str) -> None:
""" """
Stops the machine Stops the machine
Can return a task, or None if no task is returned Can return a task, or None if no task is returned
@ -166,7 +166,7 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
def shutdown_machine( def shutdown_machine(
self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str
) -> typing.Any: ) -> None:
""" """
Shutdowns the machine Shutdowns the machine
Defaults to stop_machine Defaults to stop_machine
@ -176,7 +176,7 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
def reset_machine( def reset_machine(
self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str
) -> typing.Any: ) -> None:
""" """
Resets the machine Resets the machine
Can return a task, or None if no task is returned Can return a task, or None if no task is returned
@ -186,7 +186,7 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
def suspend_machine( def suspend_machine(
self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str
) -> typing.Any: ) -> None:
""" """
Suspends the machine Suspends the machine
Defaults to shutdown_machine. Defaults to shutdown_machine.
@ -197,7 +197,7 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
@abc.abstractmethod @abc.abstractmethod
def remove_machine( def remove_machine(
self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str self, caller_instance: 'DynamicUserService | DynamicPublication', machine_id: str
) -> typing.Any: ) -> None:
""" """
Removes the machine, or queues it for removal, or whatever :) Removes the machine, or queues it for removal, or whatever :)
""" """
@ -207,7 +207,17 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
if self.has_field('maintain_on_error'): # If has been defined on own class... if self.has_field('maintain_on_error'): # If has been defined on own class...
return self.maintain_on_error.value return self.maintain_on_error.value
return False return False
def can_clean_errored_userservices(self) -> bool:
"""
Returns if this service can clean errored services. This is used to check if a service can be cleaned
from the stuck cleaner job, for example. By default, this method returns True.
"""
if self.has_field('maintain_on_error'):
return not self.maintain_on_error.value
return True
def try_graceful_shutdown(self) -> bool: def try_graceful_shutdown(self) -> bool:
if self.has_field('try_soft_shutdown'): if self.has_field('try_soft_shutdown'):
return self.try_soft_shutdown.value return self.try_soft_shutdown.value

View File

@ -44,7 +44,7 @@ from uds.core.util.model import sql_stamp_seconds
# Not imported at runtime, just for type checking # Not imported at runtime, just for type checking
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from uds import models from uds import models
from . import dynamic_service from . import service
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -52,7 +52,6 @@ logger = logging.getLogger(__name__)
# Decorator that tests that _vmid is not empty # Decorator that tests that _vmid is not empty
# Used by some default methods that require a vmid to work # Used by some default methods that require a vmid to work
def must_have_vmid(fnc: typing.Callable[[typing.Any], None]) -> typing.Callable[['DynamicUserService'], None]: def must_have_vmid(fnc: typing.Callable[[typing.Any], None]) -> typing.Callable[['DynamicUserService'], None]:
@functools.wraps(fnc) @functools.wraps(fnc)
def wrapper(self: 'DynamicUserService') -> None: def wrapper(self: 'DynamicUserService') -> None:
if self._vmid == '': if self._vmid == '':
@ -71,8 +70,8 @@ class DynamicUserService(services.UserService, autoserializable.AutoSerializable
suggested_delay = 8 suggested_delay = 8
# Some customization fields # Some customization fields
# If ip can be manually overriden # If ip can be manually overriden, normally True... (set by actor, for example)
can_set_ip: typing.ClassVar[bool] = False can_set_ip: typing.ClassVar[bool] = True
# How many times we will check for a state before giving up # How many times we will check for a state before giving up
max_state_checks: typing.ClassVar[int] = 20 max_state_checks: typing.ClassVar[int] = 20
# If keep_state_sets_error is true, and an error occurs, the machine is set to FINISHED instead of ERROR # If keep_state_sets_error is true, and an error occurs, the machine is set to FINISHED instead of ERROR
@ -223,8 +222,8 @@ class DynamicUserService(services.UserService, autoserializable.AutoSerializable
# Utility overrides for type checking... # Utility overrides for type checking...
# Probably, overriden again on child classes # Probably, overriden again on child classes
def service(self) -> 'dynamic_service.DynamicService': def service(self) -> 'service.DynamicService':
return typing.cast('dynamic_service.DynamicService', super().service()) return typing.cast('service.DynamicService', super().service())
@typing.final @typing.final
def get_name(self) -> str: def get_name(self) -> str:
@ -253,14 +252,14 @@ class DynamicUserService(services.UserService, autoserializable.AutoSerializable
@typing.final @typing.final
def get_ip(self) -> str: def get_ip(self) -> str:
# Provide self to the service, so it can some of our methods to generate the unique id if self._ip == '':
try: try:
if self._vmid: if self._vmid:
return self.service().get_machine_ip(self, self._vmid) # Provide self to the service, so it can use some of our methods for whaterever it needs
except Exception: self._ip = self.service().get_machine_ip(self, self._vmid)
logger.warning('Error obtaining IP for %s: %s', self.__class__.__name__, self._vmid, exc_info=True) except Exception:
pass logger.warning('Error obtaining IP for %s: %s', self.__class__.__name__, self._vmid, exc_info=True)
return '' return self._ip
@typing.final @typing.final
def deploy_for_user(self, user: 'models.User') -> types.states.TaskState: def deploy_for_user(self, user: 'models.User') -> types.states.TaskState:
@ -337,6 +336,7 @@ class DynamicUserService(services.UserService, autoserializable.AutoSerializable
logger.exception('Unexpected FixedUserService exception: %s', e) logger.exception('Unexpected FixedUserService exception: %s', e)
return self._error(e) return self._error(e)
@typing.final
def check_state(self) -> types.states.TaskState: def check_state(self) -> types.states.TaskState:
""" """
Check what operation is going on, and acts acordly to it Check what operation is going on, and acts acordly to it

View File

@ -41,7 +41,7 @@ from uds.core.ui import gui
# Not imported at runtime, just for type checking # Not imported at runtime, just for type checking
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from uds import models from uds import models
from .fixed_userservice import FixedUserService from .userservice import FixedUserService
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -42,7 +42,7 @@ from uds.core.util import log, autoserializable
# Not imported at runtime, just for type checking # Not imported at runtime, just for type checking
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from uds import models from uds import models
from . import fixed_service from . import service
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -136,8 +136,8 @@ class FixedUserService(services.UserService, autoserializable.AutoSerializable,
# Utility overrides for type checking... # Utility overrides for type checking...
# Probably, overriden again on child classes # Probably, overriden again on child classes
def service(self) -> 'fixed_service.FixedService': def service(self) -> 'service.FixedService':
return typing.cast('fixed_service.FixedService', super().service()) return typing.cast('service.FixedService', super().service())
@typing.final @typing.final
def get_name(self) -> str: def get_name(self) -> str:

View File

@ -34,7 +34,7 @@ import logging
import typing import typing
from uds.core import types from uds.core import types
from uds.core.services.generics.fixed_machine.fixed_userservice import FixedUserService, Operation from uds.core.services.generics.fixed.userservice import FixedUserService, Operation
from uds.core.util import autoserializable from uds.core.util import autoserializable
from .openstack import types as openstack_types from .openstack import types as openstack_types

View File

@ -35,8 +35,8 @@ import typing
from django.utils.translation import gettext_noop as _ from django.utils.translation import gettext_noop as _
from uds.core import services, types from uds.core import services, types
from uds.core.services.generics.fixed_machine.fixed_service import FixedService from uds.core.services.generics.fixed.service import FixedService
from uds.core.services.generics.fixed_machine.fixed_userservice import FixedUserService from uds.core.services.generics.fixed.userservice import FixedUserService
from uds.core.ui import gui from uds.core.ui import gui
from uds.core.util import log from uds.core.util import log

View File

@ -34,7 +34,7 @@ import logging
import typing import typing
from uds.core import types from uds.core import types
from uds.core.services.generics.fixed_machine.fixed_userservice import FixedUserService, Operation from uds.core.services.generics.fixed.userservice import FixedUserService, Operation
from uds.core.util import autoserializable from uds.core.util import autoserializable
from . import client from . import client

View File

@ -36,7 +36,7 @@ import logging
import typing import typing
from uds.core import types, consts from uds.core import types, consts
from uds.core.services.generics.dynamic_machine.dynamic_userservice import DynamicUserService, Operation from uds.core.services.generics.dynamic.userservice import DynamicUserService, Operation
from uds.core.managers.userservice import UserServiceManager from uds.core.managers.userservice import UserServiceManager
from uds.core.util import autoserializable from uds.core.util import autoserializable

View File

@ -35,7 +35,7 @@ import typing
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from uds.core import types from uds.core import types
from uds.core.services.generics.dynamic_machine.dynamic_publication import DynamicPublication from uds.core.services.generics.dynamic.publication import DynamicPublication
from uds.core.util import autoserializable from uds.core.util import autoserializable
# Not imported at runtime, just for type checking # Not imported at runtime, just for type checking

View File

@ -35,8 +35,8 @@ import typing
from django.utils.translation import gettext_noop as _ from django.utils.translation import gettext_noop as _
from uds.core import services, types from uds.core import services, types
from uds.core.services.generics.fixed_machine.fixed_service import FixedService from uds.core.services.generics.fixed.service import FixedService
from uds.core.services.generics.fixed_machine.fixed_userservice import FixedUserService from uds.core.services.generics.fixed.userservice import FixedUserService
from uds.core.ui import gui from uds.core.ui import gui
from uds.core.util import log from uds.core.util import log

View File

@ -34,9 +34,9 @@ import typing
from django.utils.translation import gettext_noop as _ from django.utils.translation import gettext_noop as _
from uds.core import types from uds.core import types
from uds.core.services.generics.dynamic_machine.dynamic_publication import DynamicPublication from uds.core.services.generics.dynamic.publication import DynamicPublication
from uds.core.services.generics.dynamic_machine.dynamic_service import DynamicService from uds.core.services.generics.dynamic.service import DynamicService
from uds.core.services.generics.dynamic_machine.dynamic_userservice import DynamicUserService from uds.core.services.generics.dynamic.userservice import DynamicUserService
from uds.core.ui import gui from uds.core.ui import gui
from uds.core.util import validators, log, fields from uds.core.util import validators, log, fields
@ -48,9 +48,9 @@ from .publication import ProxmoxPublication
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from . import client from . import client
from .provider import ProxmoxProvider from .provider import ProxmoxProvider
from uds.core.services.generics.dynamic_machine.dynamic_publication import DynamicPublication from uds.core.services.generics.dynamic.publication import DynamicPublication
from uds.core.services.generics.dynamic_machine.dynamic_service import DynamicService from uds.core.services.generics.dynamic.service import DynamicService
from uds.core.services.generics.dynamic_machine.dynamic_userservice import DynamicUserService from uds.core.services.generics.dynamic.userservice import DynamicUserService
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -34,7 +34,7 @@ import logging
import typing import typing
from uds.core import types from uds.core import types
from uds.core.services.generics.fixed_machine.fixed_userservice import FixedUserService, Operation from uds.core.services.generics.fixed.userservice import FixedUserService, Operation
from uds.core.util import log, autoserializable from uds.core.util import log, autoserializable
from . import xen_client from . import xen_client

View File

@ -35,8 +35,8 @@ import collections.abc
from django.utils.translation import gettext_noop as _ from django.utils.translation import gettext_noop as _
from uds.core import consts, services, types from uds.core import consts, services, types
from uds.core.services.generics.fixed_machine.fixed_service import FixedService from uds.core.services.generics.fixed.service import FixedService
from uds.core.services.generics.fixed_machine.fixed_userservice import FixedUserService from uds.core.services.generics.fixed.userservice import FixedUserService
from uds.core.ui import gui from uds.core.ui import gui
from uds.core.util import log from uds.core.util import log
from uds.core.util.decorators import cached from uds.core.util.decorators import cached

View File

@ -36,9 +36,9 @@ from unittest import mock
from uds import models from uds import models
from uds.core import services, types from uds.core import services, types
from uds.core.services.generics.fixed_machine import ( from uds.core.services.generics.fixed import (
fixed_service, service,
fixed_userservice, userservice,
) )
from uds.core.ui.user_interface import gui from uds.core.ui.user_interface import gui
@ -47,7 +47,7 @@ from ....utils.test import UDSTestCase
@dataclasses.dataclass @dataclasses.dataclass
class FixedServiceIterationInfo: class FixedServiceIterationInfo:
queue: list[fixed_userservice.Operation] queue: list[userservice.Operation]
service_calls: list[mock._Call] = dataclasses.field(default_factory=list) service_calls: list[mock._Call] = dataclasses.field(default_factory=list)
user_service_calls: list[mock._Call] = dataclasses.field(default_factory=list) user_service_calls: list[mock._Call] = dataclasses.field(default_factory=list)
state: str = types.states.TaskState.RUNNING state: str = types.states.TaskState.RUNNING
@ -60,11 +60,11 @@ EXPECTED_DEPLOY_ITERATIONS_INFO: typing.Final[list[FixedServiceIterationInfo]] =
# Initial state for queue # Initial state for queue
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.CREATE, userservice.Operation.CREATE,
fixed_userservice.Operation.SNAPSHOT_CREATE, userservice.Operation.SNAPSHOT_CREATE,
fixed_userservice.Operation.PROCESS_TOKEN, userservice.Operation.PROCESS_TOKEN,
fixed_userservice.Operation.START, userservice.Operation.START,
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
service_calls=[ service_calls=[
mock.call.get_and_assign_machine(), mock.call.get_and_assign_machine(),
@ -76,12 +76,12 @@ EXPECTED_DEPLOY_ITERATIONS_INFO: typing.Final[list[FixedServiceIterationInfo]] =
# (this is what our testing example does, but maybe it's not the best approach for all services) # (this is what our testing example does, but maybe it's not the best approach for all services)
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.NOP, userservice.Operation.NOP,
fixed_userservice.Operation.STOP, userservice.Operation.STOP,
fixed_userservice.Operation.SNAPSHOT_CREATE, userservice.Operation.SNAPSHOT_CREATE,
fixed_userservice.Operation.PROCESS_TOKEN, userservice.Operation.PROCESS_TOKEN,
fixed_userservice.Operation.START, userservice.Operation.START,
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
service_calls=[ service_calls=[
mock.call.process_snapshot(False, mock.ANY), mock.call.process_snapshot(False, mock.ANY),
@ -89,21 +89,21 @@ EXPECTED_DEPLOY_ITERATIONS_INFO: typing.Final[list[FixedServiceIterationInfo]] =
), ),
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.STOP, userservice.Operation.STOP,
fixed_userservice.Operation.SNAPSHOT_CREATE, userservice.Operation.SNAPSHOT_CREATE,
fixed_userservice.Operation.PROCESS_TOKEN, userservice.Operation.PROCESS_TOKEN,
fixed_userservice.Operation.START, userservice.Operation.START,
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
user_service_calls=[mock.call._stop_machine()], user_service_calls=[mock.call._stop_machine()],
), ),
# The current operation is snapshot, so check previous operation (Finished) and then process snapshot # The current operation is snapshot, so check previous operation (Finished) and then process snapshot
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.SNAPSHOT_CREATE, userservice.Operation.SNAPSHOT_CREATE,
fixed_userservice.Operation.PROCESS_TOKEN, userservice.Operation.PROCESS_TOKEN,
fixed_userservice.Operation.START, userservice.Operation.START,
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
service_calls=[ service_calls=[
mock.call.process_snapshot(False, mock.ANY), mock.call.process_snapshot(False, mock.ANY),
@ -112,16 +112,16 @@ EXPECTED_DEPLOY_ITERATIONS_INFO: typing.Final[list[FixedServiceIterationInfo]] =
), ),
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.PROCESS_TOKEN, userservice.Operation.PROCESS_TOKEN,
fixed_userservice.Operation.START, userservice.Operation.START,
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
user_service_calls=[mock.call.db_obj()], user_service_calls=[mock.call.db_obj()],
), ),
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.START, userservice.Operation.START,
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
user_service_calls=[mock.call._start_machine()], user_service_calls=[mock.call._start_machine()],
), ),
@ -129,7 +129,7 @@ EXPECTED_DEPLOY_ITERATIONS_INFO: typing.Final[list[FixedServiceIterationInfo]] =
# (or if queue is empty, but that's not the case here) # (or if queue is empty, but that's not the case here)
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
user_service_calls=[mock.call._start_checker()], user_service_calls=[mock.call._start_checker()],
state=types.states.TaskState.FINISHED, state=types.states.TaskState.FINISHED,
@ -139,22 +139,22 @@ EXPECTED_DEPLOY_ITERATIONS_INFO: typing.Final[list[FixedServiceIterationInfo]] =
EXPECTED_REMOVAL_ITERATIONS_INFO: typing.Final[list[FixedServiceIterationInfo]] = [ EXPECTED_REMOVAL_ITERATIONS_INFO: typing.Final[list[FixedServiceIterationInfo]] = [
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.REMOVE, userservice.Operation.REMOVE,
fixed_userservice.Operation.SNAPSHOT_RECOVER, userservice.Operation.SNAPSHOT_RECOVER,
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
service_calls=[mock.call.remove_and_free_machine('assigned')], service_calls=[mock.call.remove_and_free_machine('assigned')],
), ),
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.SNAPSHOT_RECOVER, userservice.Operation.SNAPSHOT_RECOVER,
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
service_calls=[mock.call.process_snapshot(True, mock.ANY)], service_calls=[mock.call.process_snapshot(True, mock.ANY)],
), ),
FixedServiceIterationInfo( FixedServiceIterationInfo(
queue=[ queue=[
fixed_userservice.Operation.FINISH, userservice.Operation.FINISH,
], ],
state=types.states.TaskState.FINISHED, state=types.states.TaskState.FINISHED,
), ),
@ -222,11 +222,11 @@ class FixedServiceTest(UDSTestCase):
service.mock.reset_mock() service.mock.reset_mock()
userservice.mock.reset_mock() userservice.mock.reset_mock()
def test_fixed_service_deploy(self) -> None: def test_service_deploy(self) -> None:
_prov, service, userservice = self.create_elements() _prov, service, userservice = self.create_elements()
self.check_iterations(service, userservice, EXPECTED_DEPLOY_ITERATIONS_INFO, removal=False) self.check_iterations(service, userservice, EXPECTED_DEPLOY_ITERATIONS_INFO, removal=False)
def test_fixed_service_deploy_no_machine(self) -> None: def test_service_deploy_no_machine(self) -> None:
_prov, service, userservice = self.create_elements() _prov, service, userservice = self.create_elements()
service.available_machines_number = 2 service.available_machines_number = 2
self.deploy_service(service, userservice) # Should be deployed without issues self.deploy_service(service, userservice) # Should be deployed without issues
@ -234,7 +234,7 @@ class FixedServiceTest(UDSTestCase):
# And now, should fail to deploy again # And now, should fail to deploy again
self.assertRaises(Exception, self.deploy_service, service, userservice) self.assertRaises(Exception, self.deploy_service, service, userservice)
def test_fixed_service_removal(self) -> None: def test_service_removal(self) -> None:
_prov, service, userservice = self.create_elements() _prov, service, userservice = self.create_elements()
# Ensure fully deployed state for userservice # Ensure fully deployed state for userservice
@ -244,7 +244,7 @@ class FixedServiceTest(UDSTestCase):
self.check_iterations(service, userservice, EXPECTED_REMOVAL_ITERATIONS_INFO, removal=True) self.check_iterations(service, userservice, EXPECTED_REMOVAL_ITERATIONS_INFO, removal=True)
class FixedTestingUserService(fixed_userservice.FixedUserService): class FixedTestingUserService(userservice.FixedUserService):
mock: 'mock.Mock' = mock.MagicMock() mock: 'mock.Mock' = mock.MagicMock()
def start_machine(self) -> None: def start_machine(self) -> None:
@ -266,14 +266,14 @@ class FixedTestingUserService(fixed_userservice.FixedUserService):
return None return None
class FixedTestingService(fixed_service.FixedService): class FixedTestingService(service.FixedService):
type_name = 'Fixed Service' type_name = 'Fixed Service'
type_type = 'FixedService' type_type = 'FixedService'
type_description = 'Fixed Service description' type_description = 'Fixed Service description'
token = fixed_service.FixedService.token token = service.FixedService.token
snapshot_type = fixed_service.FixedService.snapshot_type snapshot_type = service.FixedService.snapshot_type
machines = fixed_service.FixedService.machines machines = service.FixedService.machines
user_service_type = FixedTestingUserService user_service_type = FixedTestingUserService
first_process_called = False first_process_called = False
@ -281,15 +281,15 @@ class FixedTestingService(fixed_service.FixedService):
mock: 'mock.Mock' = mock.MagicMock() mock: 'mock.Mock' = mock.MagicMock()
def process_snapshot(self, remove: bool, userservice_instance: fixed_userservice.FixedUserService) -> None: def process_snapshot(self, remove: bool, userservice_instance: userservice.FixedUserService) -> None:
self.mock.process_snapshot(remove, userservice_instance) self.mock.process_snapshot(remove, userservice_instance)
if not remove and not self.first_process_called: if not remove and not self.first_process_called:
# We want to call start, then snapshot, again # We want to call start, then snapshot, again
# As we have snapshot on top of queue, we need to insert NOP -> STOP # As we have snapshot on top of queue, we need to insert NOP -> STOP
# This way, NOP will be consumed right now, then start will be called and then # This way, NOP will be consumed right now, then start will be called and then
# this will be called again # this will be called again
userservice_instance._push_front_op(fixed_userservice.Operation.STOP) userservice_instance._push_front_op(userservice.Operation.STOP)
userservice_instance._push_front_op(fixed_userservice.Operation.NOP) userservice_instance._push_front_op(userservice.Operation.NOP)
self.first_process_called = True self.first_process_called = True
def get_machine_name(self, vmid: str) -> str: def get_machine_name(self, vmid: str) -> str:

View File

@ -34,7 +34,6 @@
# We use commit/rollback # We use commit/rollback
from ...utils.test import UDSTransactionTestCase from ...utils.test import UDSTransactionTestCase
from uds.core.util.cache import Cache from uds.core.util.cache import Cache
from uds.core.util.decorators import cached
import time import time
# Some random chars, that include unicode non-ascci chars # Some random chars, that include unicode non-ascci chars

View File

@ -42,7 +42,7 @@ from ...utils.generators import limited_iterator
# We use transactions on some related methods (storage access, etc...) # We use transactions on some related methods (storage access, etc...)
class TestProxmovLinkedService(UDSTransactionTestCase): class TestProxmoxFixedUserService(UDSTransactionTestCase):
def setUp(self) -> None: def setUp(self) -> None:
fixtures.set_all_vm_state('stopped') fixtures.set_all_vm_state('stopped')

View File

@ -43,7 +43,7 @@ from ...utils.generators import limited_iterator
# We use transactions on some related methods (storage access, etc...) # We use transactions on some related methods (storage access, etc...)
class TestProxmovLinkedService(UDSTransactionTestCase): class TestProxmovLinkedUserService(UDSTransactionTestCase):
def setUp(self) -> None: def setUp(self) -> None:
fixtures.set_all_vm_state('stopped') fixtures.set_all_vm_state('stopped')
@ -237,14 +237,14 @@ class TestProxmovLinkedService(UDSTransactionTestCase):
self.assertEqual(state, types.states.TaskState.RUNNING) self.assertEqual(state, types.states.TaskState.RUNNING)
# Ensure DESTROY_VALIDATOR is in the queue # Ensure DESTROY_VALIDATOR is in the queue
self.assertIn(types.services.Operation.DESTROY_VALIDATOR, userservice._queue) self.assertIn(types.services.Operation.DESTROY_VALIDATOR, userservice._queue)
for _ in limited_iterator(lambda: state == types.states.TaskState.RUNNING, limit=128): for _ in limited_iterator(lambda: state == types.states.TaskState.RUNNING, limit=128):
state = userservice.check_state() state = userservice.check_state()
# Now, should be finished without any problem, no call to api should have been done # Now, should be finished without any problem, no call to api should have been done
self.assertEqual(state, types.states.TaskState.FINISHED) self.assertEqual(state, types.states.TaskState.FINISHED)
self.assertEqual(len(api.mock_calls), 0) self.assertEqual(len(api.mock_calls), 0)
# Now again, but process check_queue a couple of times before cancel # Now again, but process check_queue a couple of times before cancel
# we we have an _vmid # we we have an _vmid
state = userservice.deploy_for_user(models.User()) state = userservice.deploy_for_user(models.User())
@ -282,3 +282,9 @@ class TestProxmovLinkedService(UDSTransactionTestCase):
api.shutdown_machine.assert_called() api.shutdown_machine.assert_called()
else: else:
api.stop_machine.assert_called() api.stop_machine.assert_called()
def test_userservice_basics(self) -> None:
with fixtures.patch_provider_api() as _api:
userservice = fixtures.create_userservice_linked()
userservice.set_ip('1.2.3.4')
self.assertEqual(userservice.get_ip(), '1.2.3.4')