acex-devkit 1.16.0__tar.gz → 1.17.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 (31) hide show
  1. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/PKG-INFO +1 -1
  2. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/pyproject.toml +1 -1
  3. acex_devkit-1.17.0/src/acex_devkit/models/augment.py +38 -0
  4. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/composed_configuration.py +78 -61
  5. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/logging.py +4 -3
  6. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/README.md +0 -0
  7. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/__init__.py +0 -0
  8. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/configdiffer/__init__.py +0 -0
  9. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/configdiffer/command.py +0 -0
  10. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/configdiffer/configdiffer.py +0 -0
  11. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/configdiffer/diff.py +0 -0
  12. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/configdiffer/old_configdiffer.py +0 -0
  13. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/configdiffer/old_diff.py +0 -0
  14. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/drivers/__init__.py +0 -0
  15. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/drivers/base.py +0 -0
  16. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/drivers/base_driver.py +0 -0
  17. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/exceptions/__init__.py +0 -0
  18. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/__init__.py +0 -0
  19. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/acl_model.py +0 -0
  20. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/attribute_value.py +0 -0
  21. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/container_entry.py +0 -0
  22. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/external_value.py +0 -0
  23. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/management_connection.py +0 -0
  24. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/ned.py +0 -0
  25. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/node_response.py +0 -0
  26. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/reference.py +0 -0
  27. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/models/spanning_tree.py +0 -0
  28. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/normalizer/__init__.py +0 -0
  29. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/normalizer/base.py +0 -0
  30. {acex_devkit-1.16.0 → acex_devkit-1.17.0}/src/acex_devkit/normalizer/engine.py +0 -0
  31. {acex_devkit-1.16.0 → acex_devkit-1.17.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.16.0
3
+ Version: 1.17.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.16.0"
3
+ version = "1.17.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"
@@ -0,0 +1,38 @@
1
+ from typing import Dict, Optional
2
+ from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny
3
+
4
+ # --- Augments --------------------------------------------------------------
5
+ # Vendor/os-specific augments mount on target tree components via the
6
+ # `Augmentable` mixin. Devkit only knows about `AugmentAttributes` — the
7
+ # generic base — and uses `extra='allow'` to round-trip subclass-specific
8
+ # fields. Concrete augment payload classes (CiscoDeviceTrackingPolicy-
9
+ # Attributes, etc.) live in the backend alongside their ConfigComponent
10
+ # classes, so adding a new vendor augment requires no devkit edit.
11
+ class AugmentAttributes(BaseModel):
12
+ """
13
+ Base for vendor/os-specific augments that mount on target tree components.
14
+
15
+ Subclasses live in the backend (next to their ConfigComponent) and add
16
+ typed payload fields. `extra='allow'` lets those fields round-trip
17
+ through serialize → JSON → re-validate without devkit knowing about them.
18
+
19
+ Augments live on a target node's `augments` dict, keyed by `type`. The
20
+ target itself is implicit (it's the node carrying this augment).
21
+ """
22
+ model_config = ConfigDict(extra="allow")
23
+ type: str
24
+
25
+
26
+ class Augmentable(BaseModel):
27
+ """
28
+ Mixin that gives a target node a slot for vendor/os-specific augments.
29
+ Drivers walk `augments` per target and dispatch by augment type; targets
30
+ that no driver augments simply carry an empty dict.
31
+
32
+ `SerializeAsAny[AugmentAttributes]` makes Pydantic serialize each value
33
+ using its runtime type (the concrete subclass defined in backend),
34
+ not the declared base type. Combined with `extra='allow'` on
35
+ AugmentAttributes, this round-trips subclass-declared fields through
36
+ serialize → JSON → re-validate without devkit knowing the subclasses.
37
+ """
38
+ augments: Dict[str, SerializeAsAny[AugmentAttributes]] = {}
@@ -17,8 +17,47 @@ from acex_devkit.models.logging import (
17
17
  from acex_devkit.models.spanning_tree import SpanningTree
18
18
  from acex_devkit.models.acl_model import Acl
19
19
  from acex_devkit.models.reference import MetadataValueType, Metadata, Reference, ReferenceTo, ReferenceFrom, RenderedReference
20
+ from acex_devkit.models.augment import AugmentAttributes, Augmentable
20
21
 
21
- class SystemConfig(BaseModel):
22
+ # --- Augments --------------------------------------------------------------
23
+ # Vendor/os-specific augments mount on target tree components via the
24
+ # `Augmentable` mixin. Devkit only knows about `AugmentAttributes` — the
25
+ # generic base — and uses `extra='allow'` to round-trip subclass-specific
26
+ # fields. Concrete augment payload classes (CiscoDeviceTrackingPolicy-
27
+ # Attributes, etc.) live in the backend alongside their ConfigComponent
28
+ # classes, so adding a new vendor augment requires no devkit edit.
29
+
30
+ #class AugmentAttributes(BaseModel):
31
+ # """
32
+ # Base for vendor/os-specific augments that mount on target tree components.
33
+ #
34
+ # Subclasses live in the backend (next to their ConfigComponent) and add
35
+ # typed payload fields. `extra='allow'` lets those fields round-trip
36
+ # through serialize → JSON → re-validate without devkit knowing about them.
37
+ #
38
+ # Augments live on a target node's `augments` dict, keyed by `type`. The
39
+ # target itself is implicit (it's the node carrying this augment).
40
+ # """
41
+ # model_config = ConfigDict(extra="allow")
42
+ # type: str
43
+ #
44
+ #
45
+ #class Augmentable(BaseModel):
46
+ # """
47
+ # Mixin that gives a target node a slot for vendor/os-specific augments.
48
+ # Drivers walk `augments` per target and dispatch by augment type; targets
49
+ # that no driver augments simply carry an empty dict.
50
+ #
51
+ # `SerializeAsAny[AugmentAttributes]` makes Pydantic serialize each value
52
+ # using its runtime type (the concrete subclass defined in backend),
53
+ # not the declared base type. Combined with `extra='allow'` on
54
+ # AugmentAttributes, this round-trips subclass-declared fields through
55
+ # serialize → JSON → re-validate without devkit knowing the subclasses.
56
+ # """
57
+ # augments: Dict[str, SerializeAsAny[AugmentAttributes]] = {}
58
+
59
+
60
+ class SystemConfig(Augmentable):
22
61
  contact: Optional[AttributeValue[str]] = None
23
62
  domain_name: Optional[AttributeValue[str]] = None
24
63
  hostname: Optional[AttributeValue[str]] = None
@@ -59,7 +98,7 @@ class Ntp(BaseModel):
59
98
  config: Optional[NtpConfig] = None
60
99
  servers: Optional[Dict[str, NtpServer]] = {}
61
100
 
62
- class SshServer(BaseModel):
101
+ class SshServer(Augmentable):
63
102
  enable: Optional[AttributeValue[bool]] = None
64
103
  protocol_version: Optional[AttributeValue[int]] = AttributeValue(value=2)
65
104
  timeout: Optional[AttributeValue[int]] = None
@@ -84,7 +123,7 @@ class AuthorizedKey(ContainerEntry, BaseModel):
84
123
  public_key: Optional[AttributeValue[str]] = None
85
124
 
86
125
  class Ssh(BaseModel):
87
- config: Optional[SshServer] = None
126
+ config: Optional[SshServer] = SshServer()
88
127
  host_keys: Optional[Dict[str, AuthorizedKey]] = {}
89
128
 
90
129
  class LldpConfigAttributes(BaseModel):
@@ -122,44 +161,6 @@ class StormControlAttributes(BaseModel):
122
161
  action: Optional[AttributeValue[Literal["trap", "shutdown"]]] = None
123
162
 
124
163
 
125
- # --- Augments --------------------------------------------------------------
126
- # Vendor/os-specific augments mount on target tree components via the
127
- # `Augmentable` mixin. Devkit only knows about `AugmentAttributes` — the
128
- # generic base — and uses `extra='allow'` to round-trip subclass-specific
129
- # fields. Concrete augment payload classes (CiscoDeviceTrackingPolicy-
130
- # Attributes, etc.) live in the backend alongside their ConfigComponent
131
- # classes, so adding a new vendor augment requires no devkit edit.
132
-
133
- class AugmentAttributes(BaseModel):
134
- """
135
- Base for vendor/os-specific augments that mount on target tree components.
136
-
137
- Subclasses live in the backend (next to their ConfigComponent) and add
138
- typed payload fields. `extra='allow'` lets those fields round-trip
139
- through serialize → JSON → re-validate without devkit knowing about them.
140
-
141
- Augments live on a target node's `augments` dict, keyed by `type`. The
142
- target itself is implicit (it's the node carrying this augment).
143
- """
144
- model_config = ConfigDict(extra="allow")
145
- type: str
146
-
147
-
148
- class Augmentable(BaseModel):
149
- """
150
- Mixin that gives a target node a slot for vendor/os-specific augments.
151
- Drivers walk `augments` per target and dispatch by augment type; targets
152
- that no driver augments simply carry an empty dict.
153
-
154
- `SerializeAsAny[AugmentAttributes]` makes Pydantic serialize each value
155
- using its runtime type (the concrete subclass defined in backend),
156
- not the declared base type. Combined with `extra='allow'` on
157
- AugmentAttributes, this round-trips subclass-declared fields through
158
- serialize → JSON → re-validate without devkit knowing the subclasses.
159
- """
160
- augments: Dict[str, SerializeAsAny[AugmentAttributes]] = {}
161
-
162
-
163
164
  class InterfaceTemplateAttributes(ContainerEntry, Augmentable):
164
165
  "Reusable named set of interface attributes that interfaces can reference."
165
166
  identity_fields: ClassVar[tuple[str, ...]] = ("name",)
@@ -416,7 +417,7 @@ class SnmpPrivProtocol(str, Enum):
416
417
  AES256 = "AES256"
417
418
 
418
419
 
419
- class SnmpConfigAttributes(ContainerEntry, BaseModel):
420
+ class SnmpConfig(ContainerEntry, BaseModel):
420
421
  identity_fields: ClassVar[tuple[str, ...]] = ("name",)
421
422
  name: AttributeValue[str]
422
423
  enabled: AttributeValue[bool] = AttributeValue(value=False)
@@ -425,7 +426,7 @@ class SnmpConfigAttributes(ContainerEntry, BaseModel):
425
426
  contact: Optional[AttributeValue[str]] = None
426
427
 
427
428
 
428
- class SnmpCommunityAttributes(ContainerEntry, Augmentable):
429
+ class SnmpCommunity(ContainerEntry, Augmentable):
429
430
  identity_fields: ClassVar[tuple[str, ...]] = ("name",)
430
431
  name: AttributeValue[str]
431
432
  community: Optional[AttributeValue[str]] = None # Community string
@@ -435,7 +436,7 @@ class SnmpCommunityAttributes(ContainerEntry, Augmentable):
435
436
  ipv6acl: Optional[Reference] = None
436
437
  #source_interface: Optional[Reference] = None
437
438
 
438
- class SnmpGroupAttributes(ContainerEntry, BaseModel):
439
+ class SnmpGroup(ContainerEntry, BaseModel):
439
440
  identity_fields: ClassVar[tuple[str, ...]] = ("name",)
440
441
  name: AttributeValue[str]
441
442
  access: Optional[AttributeValue[SnmpAccess]] = AttributeValue(value=SnmpAccess.READ_ONLY)
@@ -445,7 +446,7 @@ class SnmpGroupAttributes(ContainerEntry, BaseModel):
445
446
  users: Optional[Dict[str, Reference]] = {} # Users that belong to this group. Only relevant for SNMPv3.
446
447
  views: Optional[Dict[str, Reference]] = {} # Views that this group has access to.
447
448
 
448
- class SnmpUserAttributes(ContainerEntry, BaseModel):
449
+ class SnmpUser(ContainerEntry, BaseModel):
449
450
  identity_fields: ClassVar[tuple[str, ...]] = ("username",)
450
451
  username: AttributeValue[str]
451
452
  security_level: Optional[AttributeValue[SnmpSecurityLevel]] = AttributeValue(value=SnmpSecurityLevel.NO_AUTH_NO_PRIV)
@@ -454,19 +455,19 @@ class SnmpUserAttributes(ContainerEntry, BaseModel):
454
455
  priv_protocol: Optional[AttributeValue[SnmpPrivProtocol]] = None
455
456
  priv_password: Optional[AttributeValue[str]] = None
456
457
 
457
- class SnmpViewAttributes(ContainerEntry, BaseModel):
458
- identity_fields: ClassVar[tuple[str, ...]] = ("name",)
459
- name: AttributeValue[str]
460
- oids: Optional[Dict[str, SnmpViewOidAttributes]] = {}
461
-
462
- class SnmpViewOidAttributes(ContainerEntry, BaseModel):
458
+ class SnmpView(ContainerEntry, BaseModel):
463
459
  identity_fields: ClassVar[tuple[str, ...]] = ("name",)
464
460
  name: AttributeValue[str]
465
461
  oid: AttributeValue[str]
466
462
  included: Optional[AttributeValue[bool]] = AttributeValue(value=True)
467
463
  view: Optional[AttributeValue[str]] = None
468
464
 
469
- class SnmpServerAttributes(ContainerEntry, BaseModel):
465
+ class SnmpViewAttributes(ContainerEntry, BaseModel):
466
+ identity_fields: ClassVar[tuple[str, ...]] = ("name",)
467
+ name: AttributeValue[str]
468
+ oids: Optional[Dict[str, SnmpView]] = {}
469
+
470
+ class SnmpServer(ContainerEntry, BaseModel):
470
471
  identity_fields: ClassVar[tuple[str, ...]] = ("address",)
471
472
  name: Optional[AttributeValue[str]] = None
472
473
  address: Optional[AttributeValue[str]] = None
@@ -595,7 +596,7 @@ class TrapEventOptions(str, Enum):
595
596
  BULKSTAT_COLLECTION = "bulkstat_collection"
596
597
  BULKSTAT_TRANSFER = "bulkstat_transfer"
597
598
 
598
- class TrapEventAttributes(ContainerEntry, BaseModel):
599
+ class TrapEvent(ContainerEntry, BaseModel):
599
600
  identity_fields: ClassVar[tuple[str, ...]] = ("event_name",)
600
601
  name: Optional[AttributeValue[str]] = None
601
602
  event_name: Optional[AttributeValue[TrapEventOptions]] = None
@@ -603,12 +604,12 @@ class TrapEventAttributes(ContainerEntry, BaseModel):
603
604
  #class SnmpTrap(BaseModel): ...
604
605
 
605
606
  class Snmp(BaseModel):
606
- config: Optional[Dict[str, SnmpConfigAttributes]] = {}
607
- communities: Optional[Dict[str, SnmpCommunityAttributes]] = {}
608
- groups: Optional[Dict[str, SnmpGroupAttributes]] = {}
609
- users: Optional[Dict[str, SnmpUserAttributes]] = {}
610
- trap_servers: Optional[Dict[str, SnmpServerAttributes]] = {}
611
- trap_events: Optional[Dict[str, TrapEventAttributes]] = {}
607
+ config: Optional[Dict[str, SnmpConfig]] = {}
608
+ communities: Optional[Dict[str, SnmpCommunity]] = {}
609
+ groups: Optional[Dict[str, SnmpGroup]] = {}
610
+ users: Optional[Dict[str, SnmpUser]] = {}
611
+ trap_servers: Optional[Dict[str, SnmpServer]] = {}
612
+ trap_events: Optional[Dict[str, TrapEvent]] = {}
612
613
  views: Optional[Dict[str, SnmpViewAttributes]] = {}
613
614
 
614
615
 
@@ -792,7 +793,7 @@ class VTPAttributes(Augmentable):
792
793
  class VTP(BaseModel):
793
794
  config: VTPAttributes = VTPAttributes()
794
795
 
795
- class DHCPSnoopingAttributes(BaseModel):
796
+ class DHCPSnoopingAttributes(Augmentable):
796
797
  enabled: Optional[AttributeValue[bool]] = None
797
798
  vlans: Optional[Dict[str, Reference]] = {} # VLANs where DHCP snooping is enabled, key is VLAN ID, value is reference to VLAN
798
799
  trust_interfaces: Optional[Dict[str, Reference]] = {} # Interfaces that are trusted for DHCP snooping, key is interface name, value is reference to interface
@@ -811,10 +812,16 @@ class Dhcp(BaseModel):
811
812
  snooping: Optional[DHCPSnoopingAttributes] = DHCPSnoopingAttributes()
812
813
  relay: Optional[DhcpRelay] = DhcpRelay()
813
814
 
814
- class Services(BaseModel):
815
+ class ServicesAttributes(Augmentable):
815
816
  name: Optional[AttributeValue[str]] = None
816
817
  http: Optional[AttributeValue[bool]] = None # for webgui access
817
818
  https: Optional[AttributeValue[bool]] = None # for webgui access
819
+
820
+ class Services(BaseModel):
821
+ config: Optional[ServicesAttributes] = ServicesAttributes()
822
+ #name: Optional[AttributeValue[str]] = None
823
+ #http: Optional[AttributeValue[bool]] = None # for webgui access
824
+ #https: Optional[AttributeValue[bool]] = None # for webgui access
818
825
 
819
826
  class NetflowFormat(str, Enum):
820
827
  IPFIX = "IPFIX"
@@ -950,8 +957,18 @@ class Dns(BaseModel):
950
957
  #enabled: Optional[AttributeValue[bool]] = None
951
958
  dns_servers: Optional[Dict[str, DnsServerAttributes]] = {} # key is server name, value is IP address
952
959
 
960
+
961
+ class ClockConfig(BaseModel):
962
+ timezone: Optional[AttributeValue[str]] = None
963
+
964
+
965
+ class Clock(BaseModel):
966
+ config: Optional[ClockConfig] = None
967
+
968
+
953
969
  class System(BaseModel):
954
970
  config: SystemConfig = SystemConfig()
971
+ clock: Optional[Clock] = Clock()
955
972
  aaa: Optional[TripleA] = TripleA()
956
973
  logging: Optional[LoggingComponents] = LoggingComponents() # Trying to avoid using "Logging" or "logging" as names for anything due to conflicts with standard lib.
957
974
  ntp: Optional[Ntp] = Ntp()
@@ -5,6 +5,7 @@ from acex_devkit.models.reference import Reference
5
5
  from enum import Enum
6
6
  from typing import ClassVar, Optional, Dict
7
7
 
8
+ from acex_devkit.models.augment import AugmentAttributes, Augmentable
8
9
 
9
10
  class LoggingServerBase(BaseModel): ...
10
11
  #name: str = None
@@ -36,12 +37,12 @@ class LoggingFacility(str, Enum):
36
37
  CHANGELOG = "CHANGELOG"
37
38
  INTERACTIVE_COMMANDS = "INTERACTIVE_COMMANDS"
38
39
 
39
- class LoggingConfig(BaseModel):
40
+ class LoggingConfig(Augmentable):
40
41
  rate_limit: Optional[AttributeValue[int]] = None
41
42
  severity: Optional[AttributeValue[LoggingSeverity]] = None
42
43
  buffer_size: Optional[AttributeValue[int]] = None
43
44
 
44
- class Console(BaseModel):
45
+ class Console(Augmentable):
45
46
  name: Optional[AttributeValue[str]] = None
46
47
  line_number: Optional[AttributeValue[int]] = None
47
48
  logging_synchronous: Optional[AttributeValue[bool]] = None
@@ -68,7 +69,7 @@ class VtyLine(ContainerEntry, BaseModel):
68
69
  acl_direction: Optional[AttributeValue[str]] = None # direction of ACL, either 'in' or 'out'
69
70
  acl_network_instance: Optional[AttributeValue[str]] = None # network instance where ACL is
70
71
 
71
- class FileLogging(ContainerEntry, BaseModel):
72
+ class FileLogging(ContainerEntry, Augmentable):
72
73
  identity_fields: ClassVar[tuple[str, ...]] = ("filename",)
73
74
  name: Optional[AttributeValue[str]] = None # object name
74
75
  filename: Optional[AttributeValue[str]] = None # name of the file
File without changes