acex-devkit 1.6.1__tar.gz → 1.7.0__tar.gz
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-1.6.1 → acex_devkit-1.7.0}/PKG-INFO +1 -1
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/pyproject.toml +1 -1
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/drivers/base.py +21 -22
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/drivers/base_driver.py +12 -7
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/__init__.py +1 -0
- acex_devkit-1.7.0/src/acex_devkit/models/management_connection.py +16 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/node_response.py +22 -2
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/README.md +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/__init__.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/configdiffer/__init__.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/configdiffer/command.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/configdiffer/configdiffer.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/configdiffer/diff.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/configdiffer/old_configdiffer.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/configdiffer/old_diff.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/drivers/__init__.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/exceptions/__init__.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/acl_model.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/attribute_value.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/composed_configuration.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/container_entry.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/external_value.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/logging.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/ned.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/models/spanning_tree.py +0 -0
- {acex_devkit-1.6.1 → acex_devkit-1.7.0}/src/acex_devkit/types/__init__.py +0 -0
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from typing import Any, Dict
|
|
5
5
|
|
|
6
|
+
from acex_devkit.models.node_response import NodeListItem
|
|
7
|
+
from acex_devkit.models.management_connection import ManagementConnection
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
class ParserBase(ABC):
|
|
8
11
|
"""Base class for configuration parsers."""
|
|
@@ -38,36 +41,32 @@ class RendererBase(ABC):
|
|
|
38
41
|
|
|
39
42
|
|
|
40
43
|
class TransportBase(ABC):
|
|
41
|
-
"""Base class for device transport/communication.
|
|
42
|
-
|
|
43
|
-
@abstractmethod
|
|
44
|
-
def connect(self) -> None:
|
|
45
|
-
"""Establish connection to the device."""
|
|
46
|
-
pass
|
|
44
|
+
"""Base class for device transport/communication.
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
46
|
+
Each method is self-contained — the driver decides internally
|
|
47
|
+
whether to open/close sessions per call, pool connections, or
|
|
48
|
+
make stateless requests.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
node: The node instance (identity, hostname, vendor, os, ned_id)
|
|
52
|
+
connection: Management connection (target_ip, connection_type)
|
|
53
|
+
**kwargs: Future use (credentials, options, etc.)
|
|
54
|
+
"""
|
|
56
55
|
|
|
57
56
|
@abstractmethod
|
|
58
|
-
def
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
Returns:
|
|
62
|
-
True if verification succeeded, False otherwise
|
|
63
|
-
"""
|
|
57
|
+
def get_config(self, node: NodeListItem, connection: ManagementConnection, **kwargs) -> str:
|
|
58
|
+
"""Fetch the full running configuration from a device."""
|
|
64
59
|
pass
|
|
65
60
|
|
|
66
61
|
@abstractmethod
|
|
67
|
-
def
|
|
68
|
-
"""
|
|
62
|
+
def send_config(self, node: NodeListItem, connection: ManagementConnection, commands: list[str], **kwargs) -> str:
|
|
63
|
+
"""Apply configuration commands to a device."""
|
|
69
64
|
pass
|
|
70
65
|
|
|
66
|
+
def execute(self, node: NodeListItem, connection: ManagementConnection, commands: list[str], **kwargs) -> list[str]:
|
|
67
|
+
"""Run arbitrary commands and return output per command. Opt-in per driver."""
|
|
68
|
+
raise NotImplementedError(f"{self.__class__.__name__} does not implement execute()")
|
|
69
|
+
|
|
71
70
|
|
|
72
71
|
class NetworkElementDriver:
|
|
73
72
|
"""Base class for network element drivers.
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from typing import Any, Dict
|
|
3
3
|
|
|
4
|
+
from acex_devkit.models.node_response import NodeListItem
|
|
5
|
+
from acex_devkit.models.management_connection import ManagementConnection
|
|
6
|
+
|
|
4
7
|
class ParserBase(ABC):
|
|
5
8
|
@abstractmethod
|
|
6
9
|
def parse(self, model: Dict[str, Any]) -> Any:
|
|
@@ -14,16 +17,18 @@ class RendererBase(ABC):
|
|
|
14
17
|
|
|
15
18
|
class TransportBase(ABC):
|
|
16
19
|
@abstractmethod
|
|
17
|
-
def
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def send(self, payload: Any) -> None: ...
|
|
20
|
+
def get_config(self, node: NodeListItem, connection: ManagementConnection, **kwargs) -> str:
|
|
21
|
+
"""Fetch the full running configuration from a device."""
|
|
22
|
+
pass
|
|
21
23
|
|
|
22
24
|
@abstractmethod
|
|
23
|
-
def
|
|
25
|
+
def send_config(self, node: NodeListItem, connection: ManagementConnection, commands: list[str], **kwargs) -> str:
|
|
26
|
+
"""Apply configuration commands to a device."""
|
|
27
|
+
pass
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
def execute(self, node: NodeListItem, connection: ManagementConnection, commands: list[str], **kwargs) -> list[str]:
|
|
30
|
+
"""Run arbitrary commands. Opt-in per driver."""
|
|
31
|
+
raise NotImplementedError(f"{self.__class__.__name__} does not implement execute()")
|
|
27
32
|
|
|
28
33
|
class NetworkElementDriver:
|
|
29
34
|
"""Kombinerar renderer + transport – exponeras som en plugin."""
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
from .external_value import ExternalValue
|
|
7
7
|
from .attribute_value import AttributeValue
|
|
8
8
|
from .node_response import NodeResponse, NodeListItem, LogicalNodeResponse
|
|
9
|
+
from .management_connection import ManagementConnection, ConnectionType
|
|
9
10
|
|
|
10
11
|
__all__ = [
|
|
11
12
|
ExternalValue,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ConnectionType(str, Enum):
|
|
7
|
+
ssh = "ssh"
|
|
8
|
+
telnet = "telnet"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ManagementConnection(BaseModel):
|
|
12
|
+
id: Optional[int] = None
|
|
13
|
+
node_id: Optional[int] = None
|
|
14
|
+
primary: bool = True
|
|
15
|
+
connection_type: ConnectionType = ConnectionType.ssh
|
|
16
|
+
target_ip: Optional[str] = None
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pydantic import BaseModel, Field
|
|
2
|
-
from typing import Optional, Dict, Any
|
|
2
|
+
from typing import Annotated, Optional, Dict, Any, List, Literal, Union
|
|
3
3
|
from enum import Enum
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from acex_devkit.models.composed_configuration import ComposedConfiguration
|
|
@@ -17,6 +17,7 @@ class LogicalNodeResponse(BaseModel):
|
|
|
17
17
|
|
|
18
18
|
class Asset(BaseModel):
|
|
19
19
|
id: Optional[int] = None
|
|
20
|
+
type: Literal["asset"] = "asset"
|
|
20
21
|
vendor: Optional[str] = None
|
|
21
22
|
serial_number: Optional[str] = None
|
|
22
23
|
os: Optional[str] = None
|
|
@@ -25,6 +26,25 @@ class Asset(BaseModel):
|
|
|
25
26
|
ned_id: Optional[str] = None
|
|
26
27
|
|
|
27
28
|
|
|
29
|
+
class AssetClusterAsset(BaseModel):
|
|
30
|
+
id: Optional[int] = None
|
|
31
|
+
vendor: Optional[str] = None
|
|
32
|
+
serial_number: Optional[str] = None
|
|
33
|
+
os: Optional[str] = None
|
|
34
|
+
os_version: Optional[str] = None
|
|
35
|
+
hardware_model: Optional[str] = None
|
|
36
|
+
ned_id: Optional[str] = None
|
|
37
|
+
cluster_index: Optional[int] = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AssetCluster(BaseModel):
|
|
41
|
+
id: Optional[int] = None
|
|
42
|
+
type: Literal["asset_cluster"] = "asset_cluster"
|
|
43
|
+
name: Optional[str] = None
|
|
44
|
+
ned_id: Optional[str] = None
|
|
45
|
+
assets: List[AssetClusterAsset] = []
|
|
46
|
+
|
|
47
|
+
|
|
28
48
|
class AssetRefType(str, Enum):
|
|
29
49
|
asset = "asset"
|
|
30
50
|
asset_cluster = "asset_cluster"
|
|
@@ -65,7 +85,7 @@ class NodeListItem(NodeBase):
|
|
|
65
85
|
|
|
66
86
|
class NodeResponse(NodeBase):
|
|
67
87
|
id: Optional[int] = None
|
|
68
|
-
asset: Asset
|
|
88
|
+
asset: Annotated[Union[Asset, AssetCluster], Field(discriminator="type")]
|
|
69
89
|
logical_node: LogicalNodeResponse
|
|
70
90
|
created_at: datetime
|
|
71
91
|
updated_at: Optional[datetime] = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|