mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-23 17:34:17 +03:00
Some renaming for better significance
This commit is contained in:
parent
8f98314c97
commit
9320eb3adf
@ -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
|
||||||
@ -447,6 +408,14 @@ class DynamicPublication(services.Publication, autoserializable.AutoSerializable
|
|||||||
|
|
||||||
# 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:
|
||||||
return op.name
|
return op.name
|
||||||
@ -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,
|
||||||
}
|
}
|
@ -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 :)
|
||||||
"""
|
"""
|
||||||
@ -208,6 +208,16 @@ class DynamicService(services.Service, abc.ABC): # pylint: disable=too-many-pub
|
|||||||
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
|
@ -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
|
||||||
|
self._ip = self.service().get_machine_ip(self, self._vmid)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning('Error obtaining IP for %s: %s', self.__class__.__name__, self._vmid, exc_info=True)
|
logger.warning('Error obtaining IP for %s: %s', self.__class__.__name__, self._vmid, exc_info=True)
|
||||||
pass
|
return self._ip
|
||||||
return ''
|
|
||||||
|
|
||||||
@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
|
@ -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__)
|
||||||
|
|
@ -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:
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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__)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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')
|
||||||
|
|
||||||
|
@ -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')
|
||||||
|
|
||||||
@ -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')
|
||||||
|
Loading…
Reference in New Issue
Block a user