acex-devkit 1.8.0__tar.gz → 1.10.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.
Files changed (29) hide show
  1. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/PKG-INFO +1 -1
  2. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/pyproject.toml +1 -1
  3. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/drivers/base.py +22 -3
  4. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/composed_configuration.py +103 -1
  5. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/README.md +0 -0
  6. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/__init__.py +0 -0
  7. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/configdiffer/__init__.py +0 -0
  8. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/configdiffer/command.py +0 -0
  9. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/configdiffer/configdiffer.py +0 -0
  10. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/configdiffer/diff.py +0 -0
  11. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/configdiffer/old_configdiffer.py +0 -0
  12. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/configdiffer/old_diff.py +0 -0
  13. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/drivers/__init__.py +0 -0
  14. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/drivers/base_driver.py +0 -0
  15. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/exceptions/__init__.py +0 -0
  16. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/__init__.py +0 -0
  17. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/acl_model.py +0 -0
  18. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/attribute_value.py +0 -0
  19. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/container_entry.py +0 -0
  20. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/external_value.py +0 -0
  21. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/logging.py +0 -0
  22. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/management_connection.py +0 -0
  23. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/ned.py +0 -0
  24. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/node_response.py +0 -0
  25. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/models/spanning_tree.py +0 -0
  26. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/normalizer/__init__.py +0 -0
  27. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/normalizer/base.py +0 -0
  28. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/normalizer/engine.py +0 -0
  29. {acex_devkit-1.8.0 → acex_devkit-1.10.0}/src/acex_devkit/types/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: acex-devkit
3
- Version: 1.8.0
3
+ Version: 1.10.0
4
4
  Summary: ACE-X DevKit - Development kit for building ACE-X drivers and plugins
5
5
  License: AGPL-3.0
6
6
  Keywords: automation,devkit,sdk,drivers,plugins
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "acex-devkit"
3
- version = "1.8.0"
3
+ version = "1.10.0"
4
4
  description = "ACE-X DevKit - Development kit for building ACE-X drivers and plugins"
5
5
  authors = ["Johan Lahti <johan.lahti@acebit.se>"]
6
6
  readme = "README.md"
@@ -1,6 +1,7 @@
1
1
  """Driver base classes for ACE-X network element drivers."""
2
2
 
3
3
  from abc import ABC, abstractmethod
4
+ from contextlib import contextmanager
4
5
  from typing import Any, Dict
5
6
 
6
7
  from acex_devkit.models.node_response import NodeListItem
@@ -43,9 +44,9 @@ class RendererBase(ABC):
43
44
  class TransportBase(ABC):
44
45
  """Base class for device transport/communication.
45
46
 
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.
47
+ Each method is self-contained, but transports may also expose
48
+ `session()` as a context manager so a caller can run multiple
49
+ operations against the same physical connection.
49
50
 
50
51
  Args:
51
52
  node: The node instance (identity, hostname, vendor, os, ned_id)
@@ -53,6 +54,16 @@ class TransportBase(ABC):
53
54
  **kwargs: Future use (credentials, options, etc.)
54
55
  """
55
56
 
57
+ @contextmanager
58
+ def session(self, connection: ManagementConnection, **kwargs):
59
+ """Open a reusable session for multiple ops on one device.
60
+
61
+ Default is a no-op: methods continue to open/close per call.
62
+ Drivers that benefit from connection reuse override this to
63
+ hold a single connection open for the duration of the block.
64
+ """
65
+ yield self
66
+
56
67
  @abstractmethod
57
68
  def get_config(self, node: NodeListItem, connection: ManagementConnection, **kwargs) -> str:
58
69
  """Fetch the full running configuration from a device."""
@@ -67,6 +78,14 @@ class TransportBase(ABC):
67
78
  """Run arbitrary commands and return output per command. Opt-in per driver."""
68
79
  raise NotImplementedError(f"{self.__class__.__name__} does not implement execute()")
69
80
 
81
+ def get_lldp_neighbors(self, node: NodeListItem, connection: ManagementConnection, **kwargs) -> list[dict]:
82
+ """Fetch LLDP/CDP neighbor table from a device.
83
+
84
+ Returns list of dicts with keys:
85
+ local_interface, remote_device, remote_interface, discovery_protocol
86
+ """
87
+ raise NotImplementedError(f"{self.__class__.__name__} does not implement get_lldp_neighbors()")
88
+
70
89
 
71
90
  class NetworkElementDriver:
72
91
  """Base class for network element drivers.
@@ -709,6 +709,108 @@ class Services(BaseModel):
709
709
  http: Optional[AttributeValue[bool]] = None # for webgui access
710
710
  https: Optional[AttributeValue[bool]] = None # for webgui access
711
711
 
712
+ class NetflowFormat(str, Enum):
713
+ IPFIX = "IPFIX"
714
+ NETFLOW_V9 = "NetFlow v9"
715
+ NETFLOW_V5 = "NetFlow v5"
716
+
717
+ class NetflowRecordIpv4Match(BaseModel):
718
+ # Leaf-level ipv4 matches (Cisco style "match ipv4 <field>"). True = match this field, False = No. None = Ignore the field
719
+ netflow_record: Optional[AttributeValue[str]] = None # Reference to parent record, used for easier access in config component
720
+ dscp: Optional[AttributeValue[bool]] = None
721
+ fragmentation: Optional[AttributeValue[bool]] = None
722
+ header_length: Optional[AttributeValue[bool]] = None
723
+ id: Optional[AttributeValue[bool]] = None
724
+ length: Optional[AttributeValue[bool]] = None
725
+ option: Optional[AttributeValue[bool]] = None
726
+ precedence: Optional[AttributeValue[bool]] = None
727
+ protocol: Optional[AttributeValue[bool]] = None
728
+ section: Optional[AttributeValue[str]] = None
729
+ tos: Optional[AttributeValue[bool]] = None
730
+ total_length: Optional[AttributeValue[bool]] = None
731
+ ttl: Optional[AttributeValue[bool]] = None
732
+ version: Optional[AttributeValue[bool]] = None
733
+
734
+ class NetflowRecordAttributes(BaseModel): # Cisco flow record
735
+ match_ipv4: Optional[NetflowRecordIpv4Match] = None
736
+ #match_ipv4: Optional[Dict[str, NetflowRecordIpv4Match]] = {}
737
+ application_name: Optional[AttributeValue[bool]] = None
738
+
739
+ # Escape hatch for vendor-specific match knobs not yet modeled
740
+ match_vendor_specific: Optional[AttributeValue[Dict[str, Any]]] = None # keeping a flexible option if needed. Not advertised to users.
741
+
742
+ collect_timestamp_absolute_first: Optional[AttributeValue[bool]] = None
743
+ collect_timestamp_absolute_last: Optional[AttributeValue[bool]] = None
744
+
745
+ class NetflowCollectorAttributes(BaseModel): # Cisco flow monitor
746
+ cache_inactive: Optional[AttributeValue[int]] = None
747
+ cache_active: Optional[AttributeValue[int]] = None
748
+ interfaces: Optional[Dict[str, Reference]] = {} # allow for disabling netflow on specific interfaces
749
+
750
+ class NetflowExporterOptions(BaseModel):
751
+ # Mostly timeouts atm
752
+ interface_table_timeout: Optional[AttributeValue[int]] = None
753
+ vrf_table_timeout: Optional[AttributeValue[int]] = None
754
+ sampler_table_timeout: Optional[AttributeValue[int]] = None
755
+ application_table_timeout: Optional[AttributeValue[int]] = None
756
+ application_attributes_timeout: Optional[AttributeValue[int]] = None
757
+ netflow_exporter: Optional[AttributeValue[str]] = None # Reference to parent exporter, used for easier access in config component
758
+
759
+ class NetflowExporterAttributes(ContainerEntry, BaseModel): # Cisco flow exporter
760
+ identity_fields: ClassVar[tuple[str, ...]] = ("address",)
761
+ address: Optional[AttributeValue[str]] = None
762
+ port: Optional[AttributeValue[int]] = None
763
+ format: Optional[AttributeValue[NetflowFormat]] = None
764
+ source_interface: Optional[Reference] = None
765
+ network_instance: Optional[AttributeValue[str]] = None
766
+ options: Optional[NetflowExporterOptions] = None
767
+
768
+ class NetflowGlobalConfigAttributes(BaseModel):
769
+ enabled: Optional[AttributeValue[bool]] = None
770
+ version: Optional[AttributeValue[int]] = None
771
+
772
+ class Netflow(BaseModel):
773
+ config: Optional[NetflowGlobalConfigAttributes] = None
774
+ records: Optional[Dict[str, NetflowRecordAttributes]] = {}
775
+ exporters: Optional[Dict[str, NetflowExporterAttributes]] = {}
776
+ collectors: Optional[Dict[str, NetflowCollectorAttributes]] = {}
777
+
778
+ class SflowMonitoringAttributes(BaseModel): ...
779
+
780
+ class SflowForwardingAttributes(BaseModel): ... # collector?
781
+
782
+ class SflowCollectorAttributes(ContainerEntry, BaseModel):
783
+ identity_fields: ClassVar[tuple[str, ...]] = ("address",)
784
+ address: Optional[AttributeValue[str]] = None # Destination IP address of the sFlow collector
785
+ port: Optional[AttributeValue[int]] = None # UDP
786
+ source_address: Optional[AttributeValue[str]] = None
787
+ network_instance: Optional[AttributeValue[str]] = None # VRF
788
+ interfaces: Optional[Dict[str, Reference]] = {} # allow for disabling sflow on specific interfaces
789
+
790
+ class SfloGlobalConfigAttributes(BaseModel):
791
+ enabled: Optional[AttributeValue[bool]] = None
792
+ #version: Optional[AttributeValue[int]] = None
793
+ dscp: Optional[AttributeValue[int]] = None # range: 0..63
794
+ sample_size: Optional[AttributeValue[int]] = None # Sets the maximum number of bytes to be copied from a sampled packet (content within one specific sample of a packet).
795
+ polling_interval: Optional[AttributeValue[int]] = None # seconds
796
+ ingress_sampling_rate: Optional[AttributeValue[int]] = None # sampling rate is 1/N packets. An implementation may implement the sampling rate as a statistical average, rather than a strict periodic sampling.
797
+ egress_sampling_rate: Optional[AttributeValue[int]] = None # sampling rate is 1/N packets. An implementation may implement the sampling rate as a statistical average, rather than a strict periodic sampling.
798
+
799
+ class Sflow(BaseModel):
800
+ #enabled: Optional[AttributeValue[bool]] = None
801
+ #version: Optional[AttributeValue[int]] = None
802
+ #dscp: Optional[AttributeValue[int]] = None # range: 0..63
803
+ #sample_size: Optional[AttributeValue[int]] = None
804
+ #polling_interval: Optional[AttributeValue[int]] = None
805
+ #ingress_sampling_rate: Optional[AttributeValue[int]] = None
806
+ #egress_sampling_rate: Optional[AttributeValue[int]] = None
807
+ collector: Optional[Dict[str, SflowCollectorAttributes]] = {}
808
+ # Similar structure to Netflow can be implemented here for sFlow-specific attributes
809
+
810
+ class Sampling(BaseModel):
811
+ netflow: Optional[Netflow] = Netflow()
812
+ #sflow: Optional[Sflow] = Sflow() # Sflow can be added in the future, similar structure to Netflow
813
+
712
814
  class System(BaseModel):
713
815
  config: SystemConfig = SystemConfig()
714
816
  aaa: Optional[TripleA] = TripleA()
@@ -739,7 +841,7 @@ class ComposedConfiguration(BaseModel):
739
841
  interfaces: Dict[str, InterfaceType] = {}
740
842
  network_instances: Dict[str, NetworkInstance] = {"global": NetworkInstance(name="global")}
741
843
  stp: Optional[SpanningTree] = SpanningTree()
742
-
844
+ sampling: Optional[Sampling] = Sampling()
743
845
 
744
846
  """
745
847
  GUIDELINES FOR COMPOSED CONFIGURATION:
File without changes