#
# Copyright 2021-2022 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
"""Base configuration module."""
import logging
from abc import ABC, abstractmethod
from typing import Dict, Optional
from .executor import Executor
logger = logging.getLogger(__name__)
[docs]class Base(ABC):
"""Interface for providers to configure instantiated environments.
Defines how to setup/configure an environment that has been instantiated by
a provider and prepare it for some operation, e.g. execute build. It must
account for:
(1) the OS type and version.
(2) the provided image that was launched, e.g. bootstrapping a minimal image
versus a more fully featured one.
(3) any dependencies that are required for the operation to complete, e.g.
installed applications, networking configuration, etc. This includes any
environment configuration that the application will assume is available.
:cvar compatibility_tag: Tag/Version for variant of build configuration and
setup. Any change to this version would indicate that prior [versioned]
instances are incompatible and must be cleaned. As such, any new value
should be unique to old values (e.g. incrementing). It is suggested to
extend this tag, not overwrite it, e.g.: compatibility_tag =
f"{appname}-{Base.compatibility_tag}.{apprevision}" to ensure base
compatibility levels are maintained.
"""
compatibility_tag: str = "base-v0"
[docs] @abstractmethod
def get_command_environment(
self,
) -> Dict[str, Optional[str]]:
"""Get command environment to use when executing commands.
:returns: Dictionary of environment, allowing None as a value to
indicate that a value should be unset.
"""
[docs] @abstractmethod
def setup(
self,
*,
executor: Executor,
retry_wait: float = 0.25,
timeout: Optional[float] = None,
) -> None:
"""Prepare base instance for use by the application.
Wait for environment to become ready and configure it. At completion of
setup, the executor environment should have networking up and have all
of the installed dependencies required for subsequent use by the
application.
Setup should not be called more than once in a given instance to
refresh/update the environment, use `warmup` for that.
If timeout is specified, abort operation if time has been exceeded.
:param executor: Executor for target container.
:param retry_wait: Duration to sleep() between status checks (if
required).
:param timeout: Timeout in seconds.
:raises BaseCompatibilityError: if instance is incompatible.
:raises BaseConfigurationError: on other unexpected error.
"""
[docs] @abstractmethod
def warmup(
self,
*,
executor: Executor,
retry_wait: float = 0.25,
timeout: Optional[float] = None,
) -> None:
"""Prepare a previously created and setup instance for use by the application.
Ensure the instance is still valid and wait for environment to become ready.
If timeout is specified, abort operation if time has been exceeded.
:param executor: Executor for target container.
:param retry_wait: Duration to sleep() between status checks (if required).
:param timeout: Timeout in seconds.
:raises BaseCompatibilityError: if instance is incompatible.
:raises BaseConfigurationError: on other unexpected error.
"""
[docs] @abstractmethod
def wait_until_ready(
self,
*,
executor: Executor,
retry_wait: float = 0.25,
timeout: Optional[float] = None,
) -> None:
"""Wait until base instance is ready.
Ensure minimum-required boot services are running. This would be used
when starting an environment's container/VM after already [recently]
running setup(), e.g. rebooting the instance. Allows the environment to
be used without the cost incurred by re-executing the steps
unnecessarily.
If timeout is specified, abort operation if time has been exceeded.
:param executor: Executor for target container.
:param retry_wait: Duration to sleep() between status checks (if
required).
:param timeout: Timeout in seconds.
:raises BaseCompatibilityError: if instance is incompatible.
:raises BaseConfigurationError: on other unexpected error.
"""