-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create SSH access replacements for calls to docker.exec_run() (#362)
Co-authored-by: Torsten Kilias <[email protected]> Co-authored-by: Torsten Kilias <[email protected]>
- Loading branch information
1 parent
d6fcbaa
commit 7c0e930
Showing
21 changed files
with
838 additions
and
409 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
exasol_integration_test_docker_environment/lib/base/db_os_executor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
from abc import abstractmethod | ||
import fabric | ||
import docker | ||
from docker import DockerClient | ||
from typing import Protocol, runtime_checkable | ||
from docker.models.containers import Container, ExecResult | ||
from exasol_integration_test_docker_environment \ | ||
.lib.base.ssh_access import SshKey | ||
from exasol_integration_test_docker_environment \ | ||
.lib.data.database_info import DatabaseInfo | ||
from exasol_integration_test_docker_environment.lib.docker \ | ||
import ContextDockerClient | ||
|
||
|
||
class DockerClientFactory: | ||
""" | ||
Create a Docker client. | ||
""" | ||
def __init__(self, timeout: int = 100000): | ||
self._timeout = timeout | ||
|
||
def client(self) -> DockerClient: | ||
with ContextDockerClient(timeout=self._timeout) as client: | ||
return client | ||
|
||
|
||
# Avoid TypeError: Instance and class checks can only be | ||
# used with @runtime_checkable protocols | ||
# raised by unit tests | ||
@runtime_checkable | ||
class DbOsExecutor(Protocol): | ||
""" | ||
This class provides an abstraction to execute operating system | ||
commands on the database host, e.g. inside a Docker Container. See | ||
concrete implementations in sub-classes ``DockerExecutor`` and | ||
``SshExecutor``. | ||
""" | ||
@abstractmethod | ||
def exec(self, cmd: str) -> ExecResult: | ||
... | ||
|
||
|
||
class DockerExecutor(DbOsExecutor): | ||
def __init__(self, docker_client: DockerClient, container_name: str): | ||
self._client = docker_client | ||
self._container_name = container_name | ||
self._container = None | ||
|
||
def __enter__(self): | ||
self._container = self._client.containers.get(self._container_name) | ||
return self | ||
|
||
def __exit__(self, type_, value, traceback): | ||
self.close() | ||
|
||
def __del__(self): | ||
self.close() | ||
|
||
def exec(self, cmd: str) -> ExecResult: | ||
return self._container.exec_run(cmd) | ||
|
||
def close(self): | ||
self._container = None | ||
if self._client is not None: | ||
self._client.close() | ||
self._client = None | ||
|
||
|
||
class SshExecutor(DbOsExecutor): | ||
def __init__(self, connect_string: str, key_file: str): | ||
self._connect_string = connect_string | ||
self._key_file = key_file | ||
self._connection = None | ||
|
||
def __enter__(self): | ||
key = SshKey.read_from(self._key_file) | ||
self._connection = fabric.Connection( | ||
self._connect_string, | ||
connect_kwargs={ "pkey": key.private }, | ||
) | ||
return self | ||
|
||
def __exit__(self, type_, value, traceback): | ||
self.close() | ||
|
||
def __del__(self): | ||
self.close() | ||
|
||
def exec(self, cmd: str) -> ExecResult: | ||
result = self._connection.run(cmd) | ||
output = result.stdout.encode("utf-8") | ||
return ExecResult(result.exited, output) | ||
|
||
def close(self): | ||
if self._connection is not None: | ||
self._connection.close() | ||
self._connection = None | ||
|
||
|
||
# Avoid TypeError: Instance and class checks can only be | ||
# used with @runtime_checkable protocols | ||
# raised by integration tests | ||
@runtime_checkable | ||
class DbOsExecFactory(Protocol): | ||
""" | ||
This class defines an abstract method ``executor()`` to be implemented by | ||
inheriting factories. | ||
""" | ||
|
||
@abstractmethod | ||
def executor(self) -> DbOsExecutor: | ||
""" | ||
Create an executor for executing commands inside of the operating | ||
system of the database. | ||
""" | ||
... | ||
|
||
|
||
class DockerExecFactory(DbOsExecFactory): | ||
def __init__(self, container_name: str, client_factory: DockerClientFactory): | ||
self._container_name = container_name | ||
self._client_factory = client_factory | ||
|
||
def executor(self) -> DbOsExecutor: | ||
client = self._client_factory.client() | ||
return DockerExecutor(client, self._container_name) | ||
|
||
|
||
class SshExecFactory(DbOsExecFactory): | ||
@classmethod | ||
def from_database_info(cls, info: DatabaseInfo): | ||
return SshExecFactory( | ||
f"{info.ssh_info.user}@{info.host}:{info.ports.ssh}", | ||
info.ssh_info.key_file, | ||
) | ||
|
||
def __init__(self, connect_string: str, ssh_key_file: str): | ||
self._connect_string = connect_string | ||
self._key_file = ssh_key_file | ||
|
||
def executor(self) -> DbOsExecutor: | ||
return SshExecutor(self._connect_string, self._key_file) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 7 additions & 2 deletions
9
...st_docker_environment/lib/test_environment/database_setup/find_exaplus_in_db_container.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.