Skip to content

Commit aefbef1

Browse files
committed
Rename and fix code regarding the control and command interfaces
1 parent 5ba2dc3 commit aefbef1

19 files changed

Lines changed: 547 additions & 190 deletions

‎.agents/ARCHITECTURE.md‎

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
# Architecture (Agent Reference)
22

3-
Read this before making changes to `ControlInterface`, `Ankaios`, the
4-
protocol layer, or exception handling.
5-
6-
## Control Interface
7-
8-
The SDK communicates with the Ankaios agent via a Unix socket at
9-
`/run/ankaios/control_interface` (two FIFOs: `input` and `output`). Messages
10-
are length-delimited protobuf (`_control_api` wrapping `_ank_base`).
11-
12-
`ControlInterface` runs a background reader thread that deserializes
13-
incoming messages and dispatches them to `Ankaios` via callbacks. `Ankaios`
14-
routes responses to the correct caller using a request-ID queue.
3+
Read this before making changes to `ControlInterfaceConnection`,
4+
`CommandInterfaceConnection`, `Ankaios`, the protocol layer, or exception
5+
handling.
6+
7+
## Connections
8+
9+
`Ankaios` talks to Ankaios through one of two interchangeable connections,
10+
both implementing the `Connection` abstract base class
11+
(`ankaios_sdk/_components/connection/connection.py`), picked via
12+
`ConnectionType` at construction time:
13+
14+
- **Control Interface** (`ConnectionType.CONTROL_INTERFACE`, default) — used
15+
from inside an Ankaios-managed workload. Communicates via a Unix socket at
16+
`/run/ankaios/control_interface` (two FIFOs: `input` and `output`).
17+
Messages are length-delimited protobuf (`_control_api` wrapping
18+
`_ank_base`). Implemented by `ControlInterfaceConnection`.
19+
- **Command Interface** (`ConnectionType.COMMAND_INTERFACE`) — used from
20+
outside a workload, connecting directly to the Ankaios server over gRPC.
21+
Only available if the SDK was installed with the `grpc` extra. Implemented
22+
by `CommandInterfaceConnection`.
23+
24+
Both run a background reader thread that deserializes incoming messages and
25+
dispatches them to `Ankaios` via callbacks. `Ankaios` routes responses to the
26+
correct caller using a request-ID queue.
1527

1628
`Ankaios` is the primary entry point, typically used as a context manager:
1729

‎AGENTS.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ Read these only when they apply to the task at hand:
2424
before making any code or test change: API compatibility, coverage
2525
philosophy, lint/PEP 8 enforcement, generated proto file handling.
2626
- [.agents/ARCHITECTURE.md](.agents/ARCHITECTURE.md) — required before
27-
touching `ControlInterface`, `Ankaios`, the protocol layer, or exception
28-
handling.
27+
touching `ControlInterfaceConnection`, `CommandInterfaceConnection`,
28+
`Ankaios`, the protocol layer, or exception handling.

‎DEVELOPMENT.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ from unittest.mock import patch, PropertyMock
5656
from ankaios_sdk import Ankaios, ControlInterfaceState
5757

5858
def generate_test_ankaios() -> Ankaios:
59-
with patch("ankaios_sdk.ControlInterface.connect"), patch(
60-
"ankaios_sdk.ControlInterface.connected", new_callable=PropertyMock
59+
with patch("ankaios_sdk.ControlInterfaceConnection.connect"), patch(
60+
"ankaios_sdk.ControlInterfaceConnection.connected",
61+
new_callable=PropertyMock,
6162
) as mock_connected:
6263
mock_connected.return_value = True
6364
ankaios = Ankaios()

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ a CI job or a management tool), use a gRPC connection instead:
145145
from ankaios_sdk import Ankaios, ConnectionType
146146

147147
with Ankaios(
148-
connection_type=ConnectionType.GRPC,
148+
connection_type=ConnectionType.COMMAND_INTERFACE,
149149
server_url="http://127.0.0.1:25551",
150150
) as ankaios:
151151
...

‎ankaios_sdk/_components/connection/__init__.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
2222
- Connection component:
2323
the abstract base class for a connection to Ankaios.
24-
- ControlInterface component:
24+
- ControlInterfaceConnection component:
2525
the control interface (named pipes) implementation of Connection.
26-
- GrpcConnection component:
26+
- CommandInterfaceConnection component:
2727
the command interface (gRPC server interface) implementation of
2828
Connection. Only available if the 'grpc' extra is installed.
2929
"""
@@ -32,10 +32,10 @@
3232
from .control_interface import *
3333

3434
try:
35-
from .grpc_interface import *
35+
from .command_interface import *
3636
except ImportError:
37-
# The 'grpc' extra is not installed; GrpcConnection stays unavailable,
38-
# but the rest of the SDK must still work.
37+
# The 'grpc' extra is not installed; CommandInterfaceConnection
38+
# stays unavailable, but the rest of the SDK must still work.
3939
pass
4040

4141
__all__ = [name for name in globals() if not name.startswith("_")]

ankaios_sdk/_components/connection/grpc_interface.py renamed to ankaios_sdk/_components/connection/command_interface.py

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,29 @@
1313
# SPDX-License-Identifier: Apache-2.0
1414

1515
"""
16-
This script defines the GrpcConnection class, implementing the
16+
This script defines the CommandInterfaceConnection class, implementing the
1717
Connection abstraction over a direct gRPC connection to the Ankaios
1818
server, used to connect to Ankaios from outside a workload.
1919
2020
Classes
2121
-------
2222
23-
- :class:`GrpcConnection`:
23+
- :class:`CommandInterfaceConnection`:
2424
Handles the interaction with Ankaios over gRPC.
2525
2626
Enums
2727
-----
2828
29-
- :class:`GrpcConnectionState`:
29+
- :class:`CommandInterfaceState`:
3030
Represents the state of the gRPC connection.
3131
3232
Usage
3333
-----
3434
35-
- Create a GrpcConnection instance, connect and disconnect.
35+
- Create a CommandInterfaceConnection instance, connect and disconnect.
3636
.. code-block:: python
3737
38-
conn = GrpcConnection(
38+
conn = CommandInterfaceConnection(
3939
"http://127.0.0.1:25551", <callbacks from Ankaios>
4040
)
4141
conn.connect()
@@ -44,7 +44,7 @@
4444
"""
4545

4646

47-
__all__ = ["GrpcConnection", "GrpcConnectionState"]
47+
__all__ = ["CommandInterfaceConnection", "CommandInterfaceState"]
4848

4949

5050
import queue
@@ -64,7 +64,7 @@
6464
from .connection import Connection
6565

6666

67-
class GrpcConnectionState(Enum):
67+
class CommandInterfaceState(Enum):
6868
"""The state of the gRPC connection."""
6969

7070
INITIALIZED = 1
@@ -87,11 +87,11 @@ def __str__(self) -> str:
8787

8888

8989
# pylint: disable=too-many-instance-attributes
90-
class GrpcConnection(Connection):
90+
class CommandInterfaceConnection(Connection):
9191
"""
92-
This class handles the interaction with an Ankaios server over a
93-
direct gRPC connection, playing the commander role via the
94-
CommandConnection service.
92+
This class handles the interaction with an Ankaios server over the
93+
command interface: a direct gRPC connection to the server,
94+
playing the commander role via the CommandConnection service.
9595
9696
The initial :func:`connect` attempt is never retried. Once a
9797
connection has been established, losing it is treated as
@@ -119,8 +119,8 @@ def __init__(
119119
key_pem: Optional[str] = None,
120120
) -> None:
121121
"""
122-
Initialize the GrpcConnection object. This is used to
123-
interact with an Ankaios server directly over gRPC.
122+
Initialize the CommandInterfaceConnection object. This is used to
123+
interact with an Ankaios server directly over the command interface.
124124
125125
If none of ca_pem, crt_pem and key_pem are provided, the
126126
connection is a plaintext (insecure) one. If all three are
@@ -170,31 +170,31 @@ def __init__(
170170
self._key_pem = key_pem
171171

172172
# The state of the connection must not be changed directly.
173-
self._state_value = GrpcConnectionState.TERMINATED
173+
self._state_value = CommandInterfaceState.TERMINATED
174174
self._state_lock = threading.Lock()
175175
self._channel: Optional[grpc.Channel] = None
176176
self._call = None
177177
self._write_queue: "queue.Queue" = queue.Queue()
178178
self._reader_thread: Optional[threading.Thread] = None
179179

180180
@property
181-
def _state(self) -> GrpcConnectionState:
181+
def _state(self) -> CommandInterfaceState:
182182
"""
183183
Get the current state of the connection.
184184
185185
:returns: The current state.
186-
:rtype: GrpcConnectionState
186+
:rtype: CommandInterfaceState
187187
"""
188188
with self._state_lock:
189189
return self._state_value
190190

191191
@_state.setter
192-
def _state(self, value: GrpcConnectionState) -> None:
192+
def _state(self, value: CommandInterfaceState) -> None:
193193
"""
194194
Set the current state of the connection.
195195
196196
:param value: The new state to set.
197-
:type value: GrpcConnectionState
197+
:type value: CommandInterfaceState
198198
"""
199199
with self._state_lock:
200200
self._state_value = value
@@ -207,7 +207,7 @@ def connected(self) -> bool:
207207
:returns: True if connected, False otherwise.
208208
:rtype: bool
209209
"""
210-
return self._state == GrpcConnectionState.CONNECTED
210+
return self._state == CommandInterfaceState.CONNECTED
211211

212212
def connect(self) -> None:
213213
"""
@@ -221,35 +221,35 @@ def connect(self) -> None:
221221
the connection could not be established.
222222
"""
223223
if self._state in (
224-
GrpcConnectionState.INITIALIZED,
225-
GrpcConnectionState.CONNECTED,
226-
GrpcConnectionState.RECONNECTING,
224+
CommandInterfaceState.INITIALIZED,
225+
CommandInterfaceState.CONNECTED,
226+
CommandInterfaceState.RECONNECTING,
227227
):
228228
raise ConnectionException("Already connected.")
229229

230230
# Only change the state once past the point where connecting
231231
# can still fail, so a failed attempt leaves the connection
232232
# exactly as it was and free to retry via a plain connect().
233233
call = self._open_stream()
234-
self._state = GrpcConnectionState.INITIALIZED
234+
self._state = CommandInterfaceState.INITIALIZED
235235

236236
self._reader_thread = threading.Thread(
237237
target=self._read_from_grpc, args=(call,), daemon=True
238238
)
239239
self._reader_thread.start()
240-
self._state = GrpcConnectionState.CONNECTED
240+
self._state = CommandInterfaceState.CONNECTED
241241
self._logger.debug("Connected to the Ankaios server over gRPC.")
242242

243243
def disconnect(self) -> None:
244244
"""
245245
Disconnect from the gRPC connection.
246246
"""
247-
if self._state == GrpcConnectionState.TERMINATED:
247+
if self._state == CommandInterfaceState.TERMINATED:
248248
self._logger.debug("Already disconnected.")
249249
return
250250

251251
self._logger.debug("Disconnecting..")
252-
self._state = GrpcConnectionState.TERMINATED
252+
self._state = CommandInterfaceState.TERMINATED
253253
if self._call is not None:
254254
self._call.cancel()
255255
if self._reader_thread is not None:
@@ -271,7 +271,7 @@ def write_request(self, request: Request) -> None:
271271
272272
:raises ConnectionException: If not connected.
273273
"""
274-
if self._state != GrpcConnectionState.CONNECTED:
274+
if self._state != CommandInterfaceState.CONNECTED:
275275
self._logger.error(
276276
"Could not write to the gRPC connection, not connected."
277277
)
@@ -384,7 +384,7 @@ def _read_from_grpc(self, call) -> None:
384384
for from_server in call:
385385
self._handle_from_server(from_server)
386386
except grpc.RpcError as e:
387-
if self._state == GrpcConnectionState.TERMINATED:
387+
if self._state == CommandInterfaceState.TERMINATED:
388388
# disconnect() already cancelled the call itself;
389389
# this is the expected, self-inflicted result.
390390
self._logger.debug(
@@ -397,10 +397,10 @@ def _read_from_grpc(self, call) -> None:
397397
e,
398398
)
399399

400-
if self._state == GrpcConnectionState.TERMINATED:
400+
if self._state == CommandInterfaceState.TERMINATED:
401401
return
402402

403-
self._state = GrpcConnectionState.RECONNECTING
403+
self._state = CommandInterfaceState.RECONNECTING
404404
self._logger.warning(
405405
"Lost connection to the Ankaios server, attempting to "
406406
"reconnect every %ss..",
@@ -421,14 +421,14 @@ def _reconnect(self):
421421
"""
422422
while True:
423423
time.sleep(self.RECONNECT_INTERVAL)
424-
if self._state == GrpcConnectionState.TERMINATED:
424+
if self._state == CommandInterfaceState.TERMINATED:
425425
return None
426426
try:
427427
call = self._open_stream()
428428
except ConnectionException as e:
429429
self._logger.debug("Reconnect attempt failed: '%s'", e)
430430
continue
431-
self._state = GrpcConnectionState.CONNECTED
431+
self._state = CommandInterfaceState.CONNECTED
432432
self._logger.info("Reconnected to the Ankaios server.")
433433
return call
434434

‎ankaios_sdk/_components/connection/connection.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ class ConnectionType(Enum):
4949

5050
CONTROL_INTERFACE = 1
5151
"(int): Connect via the control interface (named pipes)."
52-
GRPC = 2
53-
"(int): Connect directly to the Ankaios server over gRPC."
52+
COMMAND_INTERFACE = 2
53+
"(int): Connect via the command interface (direct gRPC)."
5454

5555
def __str__(self) -> str:
5656
"""

0 commit comments

Comments
 (0)