Skip to content

Commit c2ff207

Browse files
authored
refactoring ITDE manager interface (#97)
* refactoring ITDE manager interface * changed syntax when working with IntFlags * making mypy happy
1 parent ad39d29 commit c2ff207

File tree

3 files changed

+58
-50
lines changed

3 files changed

+58
-50
lines changed

doc/changes/changes_0.2.9.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ Post-release fixes.
99
* AI-Lab#230: Connection via SQLAlchemy fails
1010
- Enables fingerprints in the host name.
1111
- Handles correctly special characters in the password.
12-
* #89: Connecting a new AI-Lab container to the Docker DB network when the latter container restarts.
12+
* #89: Connecting a new AI-Lab container to the Docker DB network when the latter container restarts.
13+
* #93: Refactoring the ITDE manager interface.

exasol/nb_connector/itde_manager.py

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from typing import Tuple, Optional
2+
from enum import IntFlag
23

34
import docker # type: ignore
45
from docker.models.networks import Network # type: ignore
@@ -25,6 +26,14 @@
2526
NAME_SERVER_ADDRESS = "8.8.8.8"
2627

2728

29+
class ItdeContainerStatus(IntFlag):
30+
ABSENT = 0
31+
STOPPED = 1
32+
RUNNING = 3
33+
VISIBLE = 5
34+
READY = RUNNING | VISIBLE
35+
36+
2837
def bring_itde_up(conf: Secrets) -> None:
2938
"""
3039
Launches the ITDE environment using its API. Sets hardcoded environment name,
@@ -100,20 +109,21 @@ def _add_current_container_to_db_network(network_name: str) -> None:
100109
network.connect(container.id)
101110

102111

103-
def _is_current_container_not_in_db_network(network_name: str) -> bool:
112+
def _is_current_container_visible(network_name: str) -> bool:
104113
"""
105114
For the Docker Edition returns True if the current (AI-Lab) container
106-
is NOT connected to the network with the specified name. Otherwise,
107-
including the cases of other editions, returns False.
115+
is connected to the network with the specified name, otherwise False.
116+
For other editions it always returns True.
108117
"""
109118
with ContextDockerClient() as docker_client:
110119
container = _get_current_container(docker_client)
111120
if not container:
112-
return False
121+
# Not the Docker Edition
122+
return True
113123
network = _get_docker_network(docker_client, network_name)
114124
if not network:
115-
return True
116-
return container not in network.containers
125+
return False
126+
return container in network.containers
117127

118128

119129
def _get_docker_network(docker_client: docker.DockerClient, network_name: str) -> Optional[Network]:
@@ -144,61 +154,62 @@ def _get_ipv4_addresses():
144154
return ip_addresses
145155

146156

147-
def is_itde_running(conf: Secrets) -> Tuple[bool, bool]:
157+
def get_itde_status(conf: Secrets) -> ItdeContainerStatus:
148158
"""
149159
Checks if the ITDE container exists and ready to be used. In the Docker Edition that
150160
means the ITDE is running and the AI-Lab container is connected to its network. In
151161
other editions it will just check that the ITDE is running.
152162
153-
Returns two boolean flags - (exists, running).
163+
Returns the container status.
154164
155165
The name of the container is taken from the provided secret store.
156-
If the name cannot be found in the secret store the function returns False, False.
166+
If the name cannot be found there the function returns the status ABSENT.
157167
"""
158168

159169
# Try to get the names of the Docker-DB container and its network from the secret store.
160170
container_name = conf.get(AILabConfig.itde_container)
161171
network_name = conf.get(AILabConfig.itde_network)
162172
if not container_name or not network_name:
163-
return False, False
173+
return ItdeContainerStatus.ABSENT
164174

165175
# Check the existence and the status of the container using the Docker API.
166176
with ContextDockerClient() as docker_client:
167177
if docker_client.containers.list(all=True, filters={"name": container_name}):
168178
container = docker_client.containers.get(container_name)
169-
is_ready = (container.status == 'running' and not
170-
_is_current_container_not_in_db_network(network_name))
171-
return True, is_ready
172-
return False, False
179+
if container.status != 'running':
180+
return ItdeContainerStatus.STOPPED
181+
status = ItdeContainerStatus.RUNNING
182+
if _is_current_container_visible(network_name):
183+
status |= ItdeContainerStatus.VISIBLE
184+
return status
185+
return ItdeContainerStatus.ABSENT
173186

174187

175-
def start_itde(conf: Secrets) -> None:
188+
def restart_itde(conf: Secrets) -> None:
176189
"""
177190
Starts an existing ITDE container if it's not already running. In the Docker Edition
178191
connects the AI-Lab container to the Docker-DB network, unless it's already connected
179192
to it.
180193
181-
For this function to work the container must exist. If it doesn't
182-
the docker.errors.NotFound exception will be raised. Use the is_itde_running
183-
function to check if the container exists.
184-
185-
The name of the container is taken from the provided secret store, where it must
186-
exist. Otherwise, a RuntimeError will be raised.
194+
For this function to work the container must exist. If it doesn't a RuntimeError will
195+
be raised. Use the get_itde_status function to check if the container exists.
187196
"""
188197

189-
# The names of the Docker-DB container and its network should be in the secret store.
190-
container_name = conf.get(AILabConfig.itde_container)
191-
network_name = conf.get(AILabConfig.itde_network)
192-
if not container_name or not network_name:
193-
raise RuntimeError('Unable to find the name of the Docker container or its network.')
198+
status = get_itde_status(conf)
194199

195-
# Start the container using the Docker API, unless it's already running.
196-
with ContextDockerClient() as docker_client:
197-
container = docker_client.containers.get(container_name)
198-
if container.status != 'running':
200+
if status is ItdeContainerStatus.ABSENT:
201+
raise RuntimeError("The Docker-DB container doesn't exist.")
202+
203+
if ItdeContainerStatus.RUNNING not in status:
204+
container_name = conf.get(AILabConfig.itde_container)
205+
with ContextDockerClient() as docker_client:
206+
container = docker_client.containers.get(container_name)
199207
container.start()
200208

201-
_add_current_container_to_db_network(network_name)
209+
if ItdeContainerStatus.VISIBLE not in status:
210+
network_name = conf.get(AILabConfig.itde_network)
211+
if network_name:
212+
_add_current_container_to_db_network(network_name)
202213

203214

204215
def take_itde_down(conf: Secrets) -> None:

test/integration/test_itde_manager.py

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
from exasol.nb_connector.secret_store import Secrets
1616
from exasol.nb_connector.itde_manager import (
1717
bring_itde_up,
18-
is_itde_running,
19-
start_itde,
18+
get_itde_status,
19+
restart_itde,
2020
take_itde_down,
21+
ItdeContainerStatus,
2122
)
2223

2324
DB_NETWORK_NAME = "db_network_DemoDb"
@@ -70,18 +71,16 @@ def test_itde_exists_and_running(secrets):
7071

7172
try:
7273
bring_itde_up(secrets)
73-
itde_exists, itde_running = is_itde_running(secrets)
74-
assert itde_exists
75-
assert itde_running
74+
itde_status = get_itde_status(secrets)
75+
assert ItdeContainerStatus.RUNNING in itde_status
7676
finally:
7777
remove_itde()
7878

7979

8080
def test_itde_neither_exists_nor_running(secrets):
8181
remove_itde()
82-
itde_exists, itde_running = is_itde_running(secrets)
83-
assert not itde_exists
84-
assert not itde_running
82+
itde_status = get_itde_status(secrets)
83+
assert itde_status is ItdeContainerStatus.ABSENT
8584

8685

8786
def test_itde_exists_not_running(secrets):
@@ -91,9 +90,8 @@ def test_itde_exists_not_running(secrets):
9190
try:
9291
bring_itde_up(secrets)
9392
stop_itde(secrets)
94-
itde_exists, itde_running = is_itde_running(secrets)
95-
assert itde_exists
96-
assert not itde_running
93+
itde_status = get_itde_status(secrets)
94+
assert itde_status is ItdeContainerStatus.STOPPED
9795
finally:
9896
remove_itde()
9997

@@ -105,10 +103,9 @@ def test_itde_start(secrets):
105103
try:
106104
bring_itde_up(secrets)
107105
stop_itde(secrets)
108-
start_itde(secrets)
109-
itde_exists, itde_running = is_itde_running(secrets)
110-
assert itde_exists
111-
assert itde_running
106+
restart_itde(secrets)
107+
itde_status = get_itde_status(secrets)
108+
assert ItdeContainerStatus.RUNNING in itde_status
112109
finally:
113110
remove_itde()
114111

@@ -145,8 +142,7 @@ def test_take_itde_down_is_not_itde_running(secrets):
145142
try:
146143
bring_itde_up(secrets)
147144
take_itde_down(secrets)
148-
itde_exists, itde_running = is_itde_running(secrets)
149-
assert not itde_exists
150-
assert not itde_running
145+
itde_status = get_itde_status(secrets)
146+
assert itde_status is ItdeContainerStatus.ABSENT
151147
finally:
152148
remove_itde()

0 commit comments

Comments
 (0)