acex-devkit 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- acex_devkit/__init__.py +17 -0
- acex_devkit/drivers/__init__.py +15 -0
- acex_devkit/drivers/base.py +123 -0
- acex_devkit/drivers/base_driver.py +53 -0
- acex_devkit/exceptions/__init__.py +41 -0
- acex_devkit/models/__init__.py +7 -0
- acex_devkit/types/__init__.py +42 -0
- acex_devkit-1.0.0.dist-info/METADATA +87 -0
- acex_devkit-1.0.0.dist-info/RECORD +10 -0
- acex_devkit-1.0.0.dist-info/WHEEL +4 -0
acex_devkit/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""ACE-X DevKit - Development kit for building ACE-X drivers and plugins."""
|
|
2
|
+
|
|
3
|
+
__version__ = "1.0.0"
|
|
4
|
+
|
|
5
|
+
from acex_devkit.drivers import (
|
|
6
|
+
NetworkElementDriver,
|
|
7
|
+
TransportBase,
|
|
8
|
+
RendererBase,
|
|
9
|
+
ParserBase,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"NetworkElementDriver",
|
|
14
|
+
"TransportBase",
|
|
15
|
+
"RendererBase",
|
|
16
|
+
"ParserBase",
|
|
17
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Base classes for ACE-X network element drivers."""
|
|
2
|
+
|
|
3
|
+
from acex_devkit.drivers.base import (
|
|
4
|
+
NetworkElementDriver,
|
|
5
|
+
TransportBase,
|
|
6
|
+
RendererBase,
|
|
7
|
+
ParserBase,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"NetworkElementDriver",
|
|
12
|
+
"TransportBase",
|
|
13
|
+
"RendererBase",
|
|
14
|
+
"ParserBase",
|
|
15
|
+
]
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Driver base classes for ACE-X network element drivers."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Any, Dict
|
|
5
|
+
|
|
6
|
+
from acex_devkit.models.logical_node import LogicalNode
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ParserBase(ABC):
|
|
10
|
+
"""Base class for configuration parsers."""
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def parse(self, configuration: str) -> Any:
|
|
14
|
+
"""Parse device configuration into a structured model.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
configuration: Raw configuration string from device
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Parsed configuration model
|
|
21
|
+
"""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RendererBase(ABC):
|
|
26
|
+
"""Base class for configuration renderers."""
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def render(self, model: Dict[str, Any], asset: Any = None) -> Any:
|
|
30
|
+
"""Render configuration model to device-specific format.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
model: Device-agnostic configuration model
|
|
34
|
+
asset: Optional asset context
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Device-specific configuration (e.g., string, XML tree)
|
|
38
|
+
"""
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TransportBase(ABC):
|
|
43
|
+
"""Base class for device transport/communication."""
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def connect(self) -> None:
|
|
47
|
+
"""Establish connection to the device."""
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
@abstractmethod
|
|
51
|
+
def send(self, payload: Any) -> None:
|
|
52
|
+
"""Send configuration to the device.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
payload: Configuration payload to send
|
|
56
|
+
"""
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def verify(self) -> bool:
|
|
61
|
+
"""Verify configuration was applied correctly.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
True if verification succeeded, False otherwise
|
|
65
|
+
"""
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
@abstractmethod
|
|
69
|
+
def rollback(self) -> None:
|
|
70
|
+
"""Rollback configuration if verification fails."""
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class NetworkElementDriver:
|
|
75
|
+
"""Base class for network element drivers.
|
|
76
|
+
|
|
77
|
+
Combines renderer, transport, and parser to provide complete
|
|
78
|
+
configuration management for network devices.
|
|
79
|
+
|
|
80
|
+
Attributes:
|
|
81
|
+
renderer_class: Renderer class to use (must be set in subclass)
|
|
82
|
+
transport_class: Transport class to use (must be set in subclass)
|
|
83
|
+
parser_class: Parser class to use (must be set in subclass)
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
renderer_class = None
|
|
87
|
+
transport_class = None
|
|
88
|
+
parser_class = None
|
|
89
|
+
|
|
90
|
+
def __init__(self):
|
|
91
|
+
"""Initialize driver with renderer, transport, and parser instances."""
|
|
92
|
+
if self.renderer_class is None or self.transport_class is None or self.parser_class is None:
|
|
93
|
+
raise NotImplementedError(
|
|
94
|
+
"renderer_class, transport_class, and parser_class must be set in subclass"
|
|
95
|
+
)
|
|
96
|
+
self.renderer = self.renderer_class()
|
|
97
|
+
self.transport = self.transport_class()
|
|
98
|
+
self.parser = self.parser_class()
|
|
99
|
+
|
|
100
|
+
@abstractmethod
|
|
101
|
+
def render(self, logical_node: LogicalNode, asset: Any = None) -> Any:
|
|
102
|
+
"""Render logical node to device configuration.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
logical_node: Logical node containing configuration
|
|
106
|
+
asset: Optional asset context
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Rendered configuration
|
|
110
|
+
"""
|
|
111
|
+
return self.renderer.render(logical_node.model_dump(), asset)
|
|
112
|
+
|
|
113
|
+
@abstractmethod
|
|
114
|
+
def parse(self, configuration: str) -> Any:
|
|
115
|
+
"""Parse device configuration.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
configuration: Raw device configuration
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Parsed configuration model
|
|
122
|
+
"""
|
|
123
|
+
return self.parser.parse(configuration)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
|
|
4
|
+
class ParserBase(ABC):
|
|
5
|
+
@abstractmethod
|
|
6
|
+
def parse(self, model: Dict[str, Any]) -> Any:
|
|
7
|
+
"""Parsar running-config"""
|
|
8
|
+
|
|
9
|
+
class RendererBase(ABC):
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def render(self, model: Dict[str, Any]) -> Any:
|
|
12
|
+
"""Tar en device‑agnostisk konfigurationsmodell och returnerar
|
|
13
|
+
en transport‑specifik representation (t.ex. string, XML‑tree…)."""
|
|
14
|
+
|
|
15
|
+
class TransportBase(ABC):
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def connect(self) -> None: ...
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def send(self, payload: Any) -> None: ...
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def verify(self) -> bool: ...
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def rollback(self) -> None: ...
|
|
27
|
+
|
|
28
|
+
class NetworkElementDriver:
|
|
29
|
+
"""Kombinerar renderer + transport – exponeras som en plugin."""
|
|
30
|
+
renderer_class = None
|
|
31
|
+
transport_class = None
|
|
32
|
+
parser_class = None
|
|
33
|
+
|
|
34
|
+
def __init__(self):
|
|
35
|
+
if self.renderer_class is None or self.transport_class is None or self.parser_class is None:
|
|
36
|
+
raise NotImplementedError("renderer_class and transport_class must be set in subclass")
|
|
37
|
+
self.renderer = self.renderer_class()
|
|
38
|
+
self.transport = self.transport_class()
|
|
39
|
+
self.parser = self.parser_class()
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def render(self, logical_node: "LogicalNode") -> Any:
|
|
43
|
+
"""Tar en LogicalNode och returnerar en konfigurationsrepresentation."""
|
|
44
|
+
return self.renderer.render(logical_node.model_dump())
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# def apply(self, model: Dict[str, Any]) -> None:
|
|
48
|
+
# cfg = self.renderer.render(model)
|
|
49
|
+
# self.transport.connect()
|
|
50
|
+
# self.transport.send(cfg)
|
|
51
|
+
# if not self.transport.verify():
|
|
52
|
+
# self.transport.rollback()
|
|
53
|
+
# raise RuntimeError("Verification failed – rollback executed")
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Common exceptions for ACE-X DevKit."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AcexDevkitException(Exception):
|
|
5
|
+
"""Base exception for ACE-X DevKit."""
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MethodNotImplemented(AcexDevkitException):
|
|
10
|
+
"""Raised when a required method is not implemented."""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DriverException(AcexDevkitException):
|
|
15
|
+
"""Base exception for driver-related errors."""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ConnectionError(DriverException):
|
|
20
|
+
"""Raised when device connection fails."""
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ConfigurationError(DriverException):
|
|
25
|
+
"""Raised when configuration application fails."""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class VerificationError(DriverException):
|
|
30
|
+
"""Raised when configuration verification fails."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class RenderingError(DriverException):
|
|
35
|
+
"""Raised when configuration rendering fails."""
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ParsingError(DriverException):
|
|
40
|
+
"""Raised when configuration parsing fails."""
|
|
41
|
+
pass
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Type definitions and protocols for ACE-X DevKit."""
|
|
2
|
+
|
|
3
|
+
from typing import Protocol, Any, Dict, runtime_checkable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@runtime_checkable
|
|
7
|
+
class Renderable(Protocol):
|
|
8
|
+
"""Protocol for objects that can be rendered to configuration."""
|
|
9
|
+
|
|
10
|
+
def render(self, model: Dict[str, Any], asset: Any = None) -> Any:
|
|
11
|
+
"""Render configuration."""
|
|
12
|
+
...
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@runtime_checkable
|
|
16
|
+
class Parseable(Protocol):
|
|
17
|
+
"""Protocol for objects that can parse configuration."""
|
|
18
|
+
|
|
19
|
+
def parse(self, configuration: str) -> Any:
|
|
20
|
+
"""Parse configuration."""
|
|
21
|
+
...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@runtime_checkable
|
|
25
|
+
class Transportable(Protocol):
|
|
26
|
+
"""Protocol for objects that can transport configuration."""
|
|
27
|
+
|
|
28
|
+
def connect(self) -> None:
|
|
29
|
+
"""Connect to device."""
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
def send(self, payload: Any) -> None:
|
|
33
|
+
"""Send configuration."""
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
def verify(self) -> bool:
|
|
37
|
+
"""Verify configuration."""
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
def rollback(self) -> None:
|
|
41
|
+
"""Rollback configuration."""
|
|
42
|
+
...
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: acex-devkit
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: ACE-X DevKit - Development kit for building ACE-X drivers and plugins
|
|
5
|
+
License: AGPL-3.0
|
|
6
|
+
Keywords: automation,devkit,sdk,drivers,plugins
|
|
7
|
+
Author: Johan Lahti
|
|
8
|
+
Author-email: johan.lahti@acebit.se
|
|
9
|
+
Requires-Python: >=3.13,<4.0
|
|
10
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Requires-Dist: pydantic (>=2.12.5,<3.0.0)
|
|
15
|
+
Requires-Dist: typing-extensions (>=4.0.0,<5.0.0)
|
|
16
|
+
Project-URL: Homepage, https://github.com/acex-labs/acex
|
|
17
|
+
Project-URL: Repository, https://github.com/acex-labs/acex
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# ACE-X DevKit
|
|
21
|
+
|
|
22
|
+
Development kit for building ACE-X drivers and plugins.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install acex-devkit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### Building a Network Element Driver
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from acex_devkit.drivers import NetworkElementDriver, TransportBase, RendererBase, ParserBase
|
|
36
|
+
from acex_devkit.models import ComposedConfiguration
|
|
37
|
+
|
|
38
|
+
class MyRenderer(RendererBase):
|
|
39
|
+
def render(self, model: dict) -> str:
|
|
40
|
+
# Implement your rendering logic
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
class MyTransport(TransportBase):
|
|
44
|
+
def connect(self) -> None:
|
|
45
|
+
# Implement connection logic
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
def send(self, payload: Any) -> None:
|
|
49
|
+
# Implement send logic
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
def verify(self) -> bool:
|
|
53
|
+
# Implement verification logic
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
def rollback(self) -> None:
|
|
57
|
+
# Implement rollback logic
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
class MyParser(ParserBase):
|
|
61
|
+
def parse(self, configuration: str) -> ComposedConfiguration:
|
|
62
|
+
# Implement parsing logic
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
class MyDriver(NetworkElementDriver):
|
|
66
|
+
renderer_class = MyRenderer
|
|
67
|
+
transport_class = MyTransport
|
|
68
|
+
parser_class = MyParser
|
|
69
|
+
|
|
70
|
+
def render(self, configuration: ComposedConfiguration, asset):
|
|
71
|
+
return self.renderer.render(configuration, asset)
|
|
72
|
+
|
|
73
|
+
def parse(self, configuration: str) -> ComposedConfiguration:
|
|
74
|
+
return self.parser.parse(configuration)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Package Contents
|
|
78
|
+
|
|
79
|
+
- **models**: Common data models (Asset, LogicalNode, ComposedConfiguration, etc.)
|
|
80
|
+
- **drivers**: Base classes for building network element drivers
|
|
81
|
+
- **exceptions**: Common exceptions
|
|
82
|
+
- **types**: Type aliases and protocols
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
AGPL-3.0
|
|
87
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
acex_devkit/__init__.py,sha256=ANPGzAzDVEwQ24CvLvvg6pl3YH5K-Ce7PWWKtNDMOqc,318
|
|
2
|
+
acex_devkit/drivers/__init__.py,sha256=dKTc3QNJu3x49nZaf53M95k524ODeK544B90PUl9y1I,277
|
|
3
|
+
acex_devkit/drivers/base.py,sha256=njOEmzZ2glh6rNo9OHtwx7g-WL-vOVftc2akx1kMP2U,3557
|
|
4
|
+
acex_devkit/drivers/base_driver.py,sha256=p4462s8CFeZxLIM9kSJfK5viaXfGg_k3s0MvRJMQYIA,1800
|
|
5
|
+
acex_devkit/exceptions/__init__.py,sha256=KHfVL1rD1dTznMTO13t9bTsh32RdfzRilXovdXcXuLg,879
|
|
6
|
+
acex_devkit/models/__init__.py,sha256=KsrEEDA5p2VrT2FZXxZyTaFckQcFge4o9d6S5ZRIYKs,133
|
|
7
|
+
acex_devkit/types/__init__.py,sha256=4dgCg5YvI1GUUxliCgisIZWsOsXtSof0NtKmma8y6tM,1027
|
|
8
|
+
acex_devkit-1.0.0.dist-info/METADATA,sha256=2Ox2V9e4pquO9lRBPrQSAQsaKLGA69rzn3vLYe9ozXE,2405
|
|
9
|
+
acex_devkit-1.0.0.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
|
|
10
|
+
acex_devkit-1.0.0.dist-info/RECORD,,
|