Skip to content

Commit

Permalink
hosts: use built-in MultihostBackupHost instead of BaseBackupHost
Browse files Browse the repository at this point in the history
This functionality has been now included in pytest-mh.
  • Loading branch information
pbrezina committed Sep 13, 2024
1 parent 25790bb commit 039ad15
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 117 deletions.
112 changes: 7 additions & 105 deletions sssd_test_framework/hosts/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@

from __future__ import annotations

from abc import ABC, abstractmethod
from pathlib import PurePath
from typing import Any

import ldap
from ldap.ldapobject import ReconnectLDAPObject
from pytest_mh import MultihostHost
from pytest_mh.conn import Powershell
from pytest_mh import MultihostBackupHost, MultihostHost
from pytest_mh.utils.fs import LinuxFileSystem
from pytest_mh.utils.services import SystemdServices

Expand All @@ -18,17 +15,20 @@

__all__ = [
"BaseHost",
"BaseBackupHost",
"BaseDomainHost",
"BaseLDAPDomainHost",
]


class BaseHost(MultihostHost[SSSDMultihostDomain]):
class BaseHost(MultihostBackupHost[SSSDMultihostDomain]):
"""
Base class for all SSSD hosts.
"""

def __init__(self, *args, **kwargs) -> None:
# restore is handled in topology controllers
super().__init__(*args, auto_restore=False, **kwargs)

@property
def features(self) -> dict[str, bool]:
"""
Expand All @@ -37,105 +37,7 @@ def features(self) -> dict[str, bool]:
return {}


class BaseBackupHost(BaseHost, ABC):
"""
Base class for all hosts that supports automatic backup and restore.
A backup of the host is created before starting a test case and all changes
done in the test case to the host are automatically reverted when the test
run is finished.
.. warning::
There might be some limitations on what data can and can not be restored
that depends on particular host. See the documentation of each host
class to learn if a full or partial restoration is done.
"""

def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)

self.backup_data: Any | None = None
"""Backup data of vanilla state of this host."""

def pytest_setup(self) -> None:
# Make sure required services are running
try:
self.start()
except NotImplementedError:
pass

# Create backup of initial state
self.backup_data = self.backup()

def pytest_teardown(self) -> None:
self.remove_backup(self.backup_data)

def remove_backup(self, backup_data: Any | None) -> None:
"""
Remove backup data from the host.
:param backup_data: Backup data.
:type backup_data: Any | None
"""
if backup_data is None:
return

if isinstance(backup_data, PurePath):
path = str(backup_data)
else:
raise TypeError(f"Only PurePath is supported as backup_data, got {type(backup_data)}")

if isinstance(self.conn.shell, Powershell):
self.conn.exec(["Remove-Item", "-Force", "-Recurse", path])
else:
self.conn.exec(["rm", "-fr", path])

@abstractmethod
def start(self) -> None:
"""
Start required services.
:raises NotImplementedError: If start operation is not supported.
"""
pass

@abstractmethod
def stop(self) -> None:
"""
Stop required services.
:raises NotImplementedError: If stop operation is not supported.
"""
pass

@abstractmethod
def backup(self) -> Any:
"""
Backup backend data.
Returns directory or file path where the backup is stored (as PurePath)
or any Python data relevant for the backup. This data is passed to
:meth:`restore` which will use this information to restore the host to
its original state.
:return: Backup data.
:rtype: Any
"""
pass

@abstractmethod
def restore(self, backup_data: Any | None) -> None:
"""
Restore backend data.
:param backup_data: Backup data.
:type backup_data: Any | None
"""
pass


class BaseDomainHost(BaseBackupHost):
class BaseDomainHost(BaseHost):
"""
Base class for all domain (backend) hosts.
Expand Down
4 changes: 2 additions & 2 deletions sssd_test_framework/hosts/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

from pytest_mh.conn import ProcessLogLevel

from .base import BaseBackupHost, BaseLinuxHost
from .base import BaseHost, BaseLinuxHost

__all__ = [
"ClientHost",
]


class ClientHost(BaseBackupHost, BaseLinuxHost):
class ClientHost(BaseHost, BaseLinuxHost):
"""
SSSD client host object.
Expand Down
4 changes: 2 additions & 2 deletions sssd_test_framework/hosts/nfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

from pytest_mh.conn import ProcessLogLevel

from .base import BaseBackupHost, BaseLinuxHost
from .base import BaseHost, BaseLinuxHost

__all__ = [
"NFSHost",
]


class NFSHost(BaseBackupHost, BaseLinuxHost):
class NFSHost(BaseHost, BaseLinuxHost):
"""
NFS server host object.
Expand Down
15 changes: 7 additions & 8 deletions sssd_test_framework/topology_controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
from functools import partial, wraps
from typing import Any

from pytest_mh import TopologyController
from pytest_mh import MultihostBackupHost, TopologyController
from pytest_mh.conn import ProcessResult

from .config import SSSDMultihostConfig
from .hosts.ad import ADHost
from .hosts.base import BaseBackupHost
from .hosts.client import ClientHost
from .hosts.ipa import IPAHost
from .hosts.nfs import NFSHost
Expand Down Expand Up @@ -55,17 +54,17 @@ class BackupTopologyController(TopologyController[SSSDMultihostConfig]):
def __init__(self) -> None:
super().__init__()

self.backup_data: dict[BaseBackupHost, Any | None] = {}
self.backup_data: dict[MultihostBackupHost, Any | None] = {}
self.provisioned: bool = False

def init(self, *args, **kwargs):
super().init(*args, **kwargs)
self.provisioned = self.name in self.multihost.provisioned_topologies

def restore(self, hosts: dict[BaseBackupHost, Any | None]) -> None:
def restore(self, hosts: dict[MultihostBackupHost, Any | None]) -> None:
errors = []
for host, backup_data in hosts.items():
if not isinstance(host, BaseBackupHost):
if not isinstance(host, MultihostBackupHost):
continue

try:
Expand All @@ -77,10 +76,10 @@ def restore(self, hosts: dict[BaseBackupHost, Any | None]) -> None:
raise ExceptionGroup("Some hosts failed to restore to original state", errors)

def restore_vanilla(self) -> None:
restore_data: dict[BaseBackupHost, Any | None] = {}
restore_data: dict[MultihostBackupHost, Any | None] = {}

for host in self.hosts:
if not isinstance(host, BaseBackupHost):
if not isinstance(host, MultihostBackupHost):
continue

restore_data[host] = host.backup_data
Expand All @@ -93,7 +92,7 @@ def topology_teardown(self) -> None:

try:
for host, backup_data in self.backup_data.items():
if not isinstance(host, BaseBackupHost):
if not isinstance(host, MultihostBackupHost):
continue

host.remove_backup(backup_data)
Expand Down

0 comments on commit 039ad15

Please sign in to comment.