diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..99c7e42 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,168 @@ +# Diode Python SDK - Entity Examples + +Source: NetBox v4.5.0 +Generated: 2026-02-17 23:39:38Z + +## Prerequisites + +- Python 3.10 or later +- Diode SDK for Python + +## Installation + +```bash +pip install netboxlabs-diode-sdk +``` + +## Configuration + +Each example uses constants for configuration. You can modify these in the example code: + +```python +TARGET = "grpc://localhost:8080/diode" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" +``` + +## Quick Start + +Each entity example is a standalone Python file. To run an example: + +```bash +python examples/device.py +``` + +## Example Patterns + +Each example module includes three pattern functions: + +- **minimal**: Only required fields (using flat string references) +- **extended**: Required fields plus common optional fields +- **explicit**: Fully nested objects with all common fields + +Switch between patterns by uncommenting the desired function call in `main()`. + +## Available Entity Examples + +### Circuits + +- [Circuit](examples/circuit.py) +- [CircuitGroup](examples/circuit_group.py) +- [CircuitGroupAssignment](examples/circuit_group_assignment.py) +- [CircuitTermination](examples/circuit_termination.py) +- [CircuitType](examples/circuit_type.py) +- [Provider](examples/provider.py) +- [ProviderAccount](examples/provider_account.py) +- [ProviderNetwork](examples/provider_network.py) +- [VirtualCircuit](examples/virtual_circuit.py) +- [VirtualCircuitTermination](examples/virtual_circuit_termination.py) +- [VirtualCircuitType](examples/virtual_circuit_type.py) + +### DCIM + +- [Cable](examples/cable.py) +- [CablePath](examples/cable_path.py) +- [CableTermination](examples/cable_termination.py) +- [ConsolePort](examples/console_port.py) +- [ConsoleServerPort](examples/console_server_port.py) +- [Device](examples/device.py) +- [DeviceBay](examples/device_bay.py) +- [DeviceRole](examples/device_role.py) +- [DeviceType](examples/device_type.py) +- [FrontPort](examples/front_port.py) +- [Interface](examples/interface_example.py) +- [InventoryItem](examples/inventory_item.py) +- [InventoryItemRole](examples/inventory_item_role.py) +- [Location](examples/location.py) +- [Manufacturer](examples/manufacturer.py) +- [Module](examples/module.py) +- [ModuleBay](examples/module_bay.py) +- [ModuleType](examples/module_type.py) +- [ModuleTypeProfile](examples/module_type_profile.py) +- [Platform](examples/platform.py) +- [PowerFeed](examples/power_feed.py) +- [PowerOutlet](examples/power_outlet.py) +- [PowerPanel](examples/power_panel.py) +- [PowerPort](examples/power_port.py) +- [Rack](examples/rack.py) +- [RackReservation](examples/rack_reservation.py) +- [RackRole](examples/rack_role.py) +- [RackType](examples/rack_type.py) +- [RearPort](examples/rear_port.py) +- [Region](examples/region.py) +- [Site](examples/site.py) +- [SiteGroup](examples/site_group.py) +- [VirtualChassis](examples/virtual_chassis.py) +- [VirtualDeviceContext](examples/virtual_device_context.py) + +### Extras + +- [CustomField](examples/custom_field.py) +- [CustomFieldChoiceSet](examples/custom_field_choice_set.py) +- [CustomLink](examples/custom_link.py) +- [JournalEntry](examples/journal_entry.py) +- [Tag](examples/tag.py) + +### IPAM + +- [ASN](examples/asn.py) +- [ASNRange](examples/asn_range.py) +- [Aggregate](examples/aggregate.py) +- [FHRPGroup](examples/fhrp_group.py) +- [FHRPGroupAssignment](examples/fhrp_group_assignment.py) +- [IPAddress](examples/ip_address.py) +- [IPRange](examples/ip_range.py) +- [MACAddress](examples/mac_address.py) +- [Prefix](examples/prefix.py) +- [RIR](examples/rir.py) +- [Role](examples/role.py) +- [RouteTarget](examples/route_target.py) +- [Service](examples/service.py) +- [VLAN](examples/vlan.py) +- [VLANGroup](examples/vlan_group.py) +- [VLANTranslationPolicy](examples/vlan_translation_policy.py) +- [VLANTranslationRule](examples/vlan_translation_rule.py) +- [VRF](examples/vrf.py) + +### Other + +- [DeviceConfig](examples/device_config.py) + +### Tenancy + +- [Contact](examples/contact.py) +- [ContactAssignment](examples/contact_assignment.py) +- [ContactGroup](examples/contact_group.py) +- [ContactRole](examples/contact_role.py) +- [Owner](examples/owner.py) +- [OwnerGroup](examples/owner_group.py) +- [Tenant](examples/tenant.py) +- [TenantGroup](examples/tenant_group.py) + +### VPN + +- [IKEPolicy](examples/ike_policy.py) +- [IKEProposal](examples/ike_proposal.py) +- [IPSecPolicy](examples/ip_sec_policy.py) +- [IPSecProfile](examples/ip_sec_profile.py) +- [IPSecProposal](examples/ip_sec_proposal.py) +- [L2VPN](examples/l2vpn.py) +- [L2VPNTermination](examples/l2vpn_termination.py) +- [Tunnel](examples/tunnel.py) +- [TunnelGroup](examples/tunnel_group.py) +- [TunnelTermination](examples/tunnel_termination.py) + +### Virtualization + +- [Cluster](examples/cluster.py) +- [ClusterGroup](examples/cluster_group.py) +- [ClusterType](examples/cluster_type.py) +- [VMInterface](examples/vm_interface.py) +- [VirtualDisk](examples/virtual_disk.py) +- [VirtualMachine](examples/virtual_machine.py) + +### Wireless + +- [WirelessLAN](examples/wireless_lan.py) +- [WirelessLANGroup](examples/wireless_lan_group.py) +- [WirelessLink](examples/wireless_link.py) diff --git a/docs/entities.md b/docs/entities.md index d320391..5e8e655 100644 --- a/docs/entities.md +++ b/docs/entities.md @@ -1,1412 +1,3 @@ -# Supported Entities +# Diode Supported Entities -## Device - -Attributes: - -* `name` (str) - device name -* `device_type` (str, [DeviceType](#device-type)) - device type name or DeviceType entity -* `platform` (str, [Platform](#platform)) - platform name or Platform entity -* `manufacturer` (str, [Manufacturer](#manufacturer)) - manufacturer name or Manufacturer entity -* `site` (str, [Site](#site)) - site name or Site entity -* `role` (str, [Role](#role)) - role name or Role entity -* `serial` (str) - serial number -* `asset_tag` (str) - asset tag -* `status` (str) - status (e.g. `active`, `planned`, `staged`, `failed`, `inventory`, `decommissioning`, `offine`) -* `comments` (str) - comments -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Device, - DeviceType, - Entity, - Manufacturer, - Platform, - Role, - Site, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - Device entity with only a name provided will attempt to create or update a device with - the given name and placeholders (i.e. "undefined") for other nested objects types - (e.g. DeviceType, Platform, Site, Role) required by NetBox. - """ - - device = Device(name="Device A") - - entities.append(Entity(device=device)) - - """ - Device entity using flat data structure. - """ - - device_flat = Device( - name="Device A", - device_type="Device Type A", - platform="Platform A", - manufacturer="Manufacturer A", - site="Site ABC", - role="Role ABC", - serial="123456", - asset_tag="123456", - status="active", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(device=device_flat)) - - """ - Device entity using explicit data structure. - """ - - device_explicit = Device( - name="Device A", - device_type=DeviceType( - model="Device Type A", manufacturer=Manufacturer(name="Manufacturer A") - ), - platform=Platform( - name="Platform A", manufacturer=Manufacturer(name="Manufacturer A") - ), - site=Site(name="Site ABC"), - role=Role(name="Role ABC", tags=["tag 1", "tag 3"]), - serial="123456", - asset_tag="123456", - status="active", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(device=device_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() -``` - -## Interface - -Attributes: - -* `name` (str) - interface name -* `device` (str, [Device](#device)) - device name or Device entity -* `device_type` (str, [DeviceType](#device-type)) - device type name or DeviceType entity -* `role` (str, [Role](#role)) - role name or Role entity -* `platform` (str, [Platform](#platform)) - platform name or Platform entity -* `manufacturer` (str, [Manufacturer](#manufacturer)) - manufacturer name or Manufacturer entity -* `site` (str, [Site](#site)) - site name or Site entity -* `type` (str) - interface type (e.g. `virtual`, `other`, etc.) -* `enabled` (bool) - is the interface enabled -* `mtu` (int) - maximum transmission unit -* `mac_address` (str) - MAC address -* `speed` (int) - speed -* `wwn` (str) - world wide name -* `mgmt_only` (bool) - is the interface for management only -* `description` (str) - description -* `mark_connected` (bool) - mark connected -* `mode` (str) - mode (`access`, `tagged`, `tagged-all`) -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Device, - DeviceType, - Entity, - Interface, - Manufacturer, - Platform, - Role, - Site, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - Interface entity with only a name provided will attempt to create or update an interface with - the given name and placeholders (i.e. "undefined") for other nested objects types - (e.g. Device, DeviceType, Platform, Site, Role) required by NetBox. - """ - - interface = Interface(name="Interface A") - - entities.append(Entity(interface=interface)) - - """ - Interface entity using flat data structure. - """ - - interface_flat = Interface( - name="Interface A", - device="Device A", - device_type="Device Type A", - role="Role ABC", - platform="Platform A", - site="Site ABC", - type="virtual", - enabled=True, - mtu=1500, - mac_address="00:00:00:00:00:00", - description="Interface A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(interface=interface_flat)) - - """ - Interface entity using explicit data structure. - """ - - interface_explicit = Interface( - name="Interface A", - device=Device( - name="Device A", - device_type=DeviceType( - model="Device Type A", - manufacturer=Manufacturer(name="Manufacturer A"), - ), - platform=Platform( - name="Platform A", manufacturer=Manufacturer(name="Manufacturer A") - ), - site=Site(name="Site ABC"), - role=Role(name="Role ABC", tags=["tag 1", "tag 3"]), - ), - type="virtual", - enabled=True, - mtu=1500, - mac_address="00:00:00:00:00:00", - description="Interface A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(interface=interface_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Device Type - -Attributes: - -* `model` (str) - device type model -* `slug` (str) - slug -* `manufacturer` (str, [Manufacturer](#manufacturer)) - manufacturer name or Manufacturer entity -* `description` (str) - description -* `comments` (str) - comments -* `part_number` (str) - part number -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - DeviceType, - Entity, - Manufacturer, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - DeviceType entity with only a name provided will attempt to create or update a device type with - the given name and placeholder (i.e. "undefined") for nested Manufacturer object type - required by NetBox. - """ - - device_type = DeviceType(model="Device Type A") - - entities.append(Entity(device_type=device_type)) - - """ - DeviceType entity using flat data structure. - """ - - device_type_flat = DeviceType( - model="Device Type A", - manufacturer="Manufacturer A", - part_number="123456", - description="Device Type A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(device_type=device_type_flat)) - - """ - DeviceType entity using explicit data structure. - """ - - device_type_explicit = DeviceType( - model="Device Type A", - manufacturer=Manufacturer( - name="Manufacturer A", - description="Manufacturer A description", - tags=["tag 1", "tag 2"], - ), - part_number="123456", - description="Device Type A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(device_type=device_type_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Platform - -Attributes: - -* `name` (str) - platform name -* `slug` (str) - slug -* `manufacturer` (str, [Manufacturer](#manufacturer)) - manufacturer name or Manufacturer entity -* `description` (str) - description -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - Manufacturer, - Platform, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - Platform entity with only a name provided will attempt to create or update a platform with - the given name and placeholders (i.e. "undefined") for other nested objects types (e.g. Manufacturer) - required by NetBox. - """ - - platform = Platform( - name="Platform A", - ) - - entities.append(Entity(platform=platform)) - - """ - Platform entity using flat data structure. - """ - - platform_flat = Platform( - name="Platform A", - manufacturer="Manufacturer A", - description="Platform A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(platform=platform_flat)) - - """ - Platform entity using explicit data structure. - """ - - platform_explicit = Platform( - name="Platform A", - manufacturer=Manufacturer(name="Manufacturer A", tags=["tag 1", "tag 3"]), - description="Platform A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(platform=platform_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Manufacturer - -Attributes: - -* `name` (str) - manufacturer name -* `slug` (str) - slug -* `description` (str) - description -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - Manufacturer, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - Manufacturer entity. - """ - - manufacturer = Manufacturer( - name="Manufacturer A", - description="Manufacturer A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(manufacturer=manufacturer)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Site - -Attributes: - -* `name` (str) - site name -* `slug` (str) - slug -* `status` (str) - status (`active`, `planned`, `retired`, `staging`, `decommissioning`) -* `facility` (str) - facility -* `time_zone` (str) - time zone -* `description` (str) - description -* `comments` (str) - comments -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - Site, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - Site entity. - """ - - site = Site( - name="Site A", - status="active", - facility="Data Center 1", - time_zone="UTC", - description="Site A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(site=site)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Role - -Attributes: - -* `name` (str) - role name -* `slug` (str) - slug -* `color` (str) - color -* `description` (str) - description -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - Role, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - Role entity. - """ - - role = Role( - name="Role A", - slug="role-a", - color="ffffff", - description="Role A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(device_role=role)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## IP Address - -Attributes: - -* `address` (str) - IP address -* `interface` (str, [Interface](#interface)) - interface name or Interface entity -* `device` (str, [Device](#device)) - device name or Device entity -* `device_type` (str, [DeviceType](#device-type)) - device type name or DeviceType entity -* `device_role` (str, [Role](#role)) - device role name or Role entity -* `platform` (str, [Platform](#platform)) - platform name or Platform entity -* `manufacturer` (str, [Manufacturer](#manufacturer)) - manufacturer name or Manufacturer entity -* `site` (str, Site) - site name or Site entity -* `status` (str) - status (`active`, `reserved`, `deprecated`, `dhcp`, `slaac`) -* `role` (str) - role (`loopback`, `secondary`, `anycast`, `vip`, `vrrp`, `hsrp`, `glbp`, `carp`) -* `dns_name` (str) - DNS name -* `description` (str) - description -* `comments` (str) - comments -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Device, - DeviceType, - Entity, - Interface, - IPAddress, - Manufacturer, - Platform, - Role, - Site, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - IPAddress entity with only an address provided will attempt to create or update an IP address with - the given address and placeholders (i.e. "undefined") for other nested objects types - (e.g. Interface, Device, DeviceType, Platform, Site, Role) required by NetBox. - """ - - ip_address = IPAddress( - address="192.168.0.1/24", - ) - - entities.append(Entity(ip_address=ip_address)) - - """ - IPAddress entity using flat data structure. - """ - - ip_address_flat = IPAddress( - address="192.168.0.1/24", - interface="Interface ABC", - device="Device ABC", - device_type="Device Type ABC", - device_role="Role ABC", - platform="Platform ABC", - manufacturer="Cisco", - site="Site ABC", - status="active", - role="Role ABC", - description="IP Address A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag1", "tag2"], - ) - - entities.append(Entity(ip_address=ip_address_flat)) - - """ - IPAddress entity using explicit data structure. - """ - - ip_address_explicit = IPAddress( - address="192.168.0.1/24", - interface=Interface( - name="Interface ABC", - device=Device( - name="Device ABC", - device_type=DeviceType( - model="Device Type ABC", manufacturer=Manufacturer(name="Cisco") - ), - platform=Platform( - name="Platform ABC", manufacturer=Manufacturer(name="Cisco") - ), - site=Site(name="Site ABC"), - role=Role(name="Role ABC", tags=["tag1", "tag3"]), - ), - ), - status="active", - role="Role ABC", - description="IP Address A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag1", "tag2"], - ) - - entities.append(Entity(ip_address=ip_address_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Prefix - -Attributes: - -* `prefix` (str) - prefix -* `site` (str, [Site](#site)) - site name or Site entity -* `status` (str) - status (`active`, `reserved`, `deprecated`, `container`) -* `is_pool` (bool) - is pool -* `mark_utilized` (bool) - mark utilized -* `description` (str) - description -* `comments` (str) - comments -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - Prefix, - Site, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - Prefix entity with only a prefix provided will attempt to create or update a prefix with - the given prefix and placeholders (i.e. "undefined") for other nested objects types (e.g. Site) - required by NetBox. - """ - - prefix = Prefix( - prefix="192.168.0.0/32", - ) - - entities.append(Entity(prefix=prefix)) - - """ - Prefix entity using flat data structure. - """ - - prefix_flat = Prefix( - prefix="192.168.0.0/32", - site="Site ABC", - status="active", - is_pool=True, - mark_utilized=True, - description="Prefix A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(prefix=prefix_flat)) - - """ - Prefix entity using explicit data structure. - """ - - prefix_explicit = Prefix( - prefix="192.168.0.0/32", - site=Site( - name="Site ABC", - status="active", - facility="Data Center 1", - time_zone="UTC", - description="Site A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - is_pool=True, - mark_utilized=True, - description="Prefix A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(prefix=prefix_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Cluster Type - -Attributes: - -* `name` (str) - cluster type name -* `slug` (str) - slug -* `description` (str) - description -* `tags` (list) - tags - - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - ClusterType, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - ClusterType entity. - """ - - cluster_type = ClusterType( - name="Cluster Type A", - description="Cluster Type A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(cluster_type=cluster_type)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Cluster Group - -Attributes: - -* `name` (str) - cluster group name -* `slug` (str) - slug -* `description` (str) - description -* `tags` (list) - tags - - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - ClusterGroup, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - ClusterGroup entity. - """ - - cluster_group = ClusterGroup( - name="Cluster Group A", - description="Cluster Group A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(cluster_group=cluster_group)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Cluster - -Attributes: - -* `name` (str) - cluster name -* `type` (str, [ClusterType](#cluster-type)) - cluster type name or ClusterType entity -* `group` (str, [ClusterGroup](#cluster-group)) - cluster group name or ClusterGroup entity -* `site` (str, [Site](#site)) - site name or Site entity -* `status` (str) - status (`offline`, `active`, `planned`, `staged`, `failed`, `decommissioning`) -* `description` (str) - description -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - Cluster, - ClusterGroup, - ClusterType, - Site, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - Cluster entity with only a name provided will attempt to create or update a cluster with - the given name and placeholders (i.e. "undefined") for other nested objects types - (e.g. ClusterGroup, ClusterType, Site) required by NetBox. - """ - - cluster = Cluster(name="Cluster A") - - entities.append(Entity(cluster=cluster)) - - """ - Cluster entity using flat data structure. - """ - - cluster_flat = Cluster( - name="Cluster A", - type="Cluster Type", - group="Cluster Group", - site="Site ABC", - status="active", - description="Cluster A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(cluster=cluster_flat)) - - """ - Cluster entity using explicit data structure. - """ - - cluster_explicit = Cluster( - name="Cluster A", - type = ClusterType( - name="Cluster Type A", - description="Cluster Type description", - tags=["tag 1", "tag 2"], - ), - group = ClusterGroup( - name="Cluster Group A", - description="Cluster Group description", - tags=["tag 1", "tag 2"], - ), - site=Site( - name="Site ABC", - status="active", - facility="Data Center 1", - time_zone="UTC", - description="Site A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - description="Cluster A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(cluster=cluster_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Virtual Machine - -Attributes: - -* `name` (str) - virtual machine name -* `status` (str) - status (`offline`, `active`, `planned`, `staged`, `failed`, `decommissioning`) -* `site` (str, [Site](#site)) - site name or Site entity -* `cluster` (str, [Cluster](#cluster)) - cluster name or Cluster entity -* `role` (str, [Role](#role)) - role name or Role entity -* `device` (str, [Device](#device)) - device name or Device entity -* `platform` (str, [Platform](#platform)) - platform name or Platform entity -* `vcpus` (int) - virtual machine CPU number -* `memory` (int) - virtual machine memory -* `disk` (int) - virtual machine disk size -* `description` (str) - description -* `comments` (str) - comments -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - VirtualMachine, - Cluster, - ClusterGroup, - ClusterType, - Device, - DeviceType, - Manufacturer, - Platform, - Role, - Site, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - VirtualMachine entity with only a name provided will attempt to create or update a name with - the given name and placeholders (i.e. "undefined") for other nested objects types (e.g. Site, - Role, Cluster, Platform, Device) required by NetBox. - """ - - virtual_machine = VirtualMachine(name="VM A") - - entities.append(Entity(virtual_machine=virtual_machine)) - - """ - VirtualMachine entity using flat data structure. - """ - - virtual_machine_flat = VirtualMachine( - name="VM A", - status="active", - cluster="Cluster Type A", - site="Site ABC", - role="Role ABC", - device="Device A", - platform="Platform A", - vcpus=8, - memory=12128, - disk=16786, - description="Virtual Machine A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(virtual_machine=virtual_machine_flat)) - - """ - VirtualMachine entity using explicit data structure. - """ - - virtual_machine_explicit = VirtualMachine( - name="VM A", - status="active", - cluster=Cluster( - name="Cluster A", - type=ClusterType( - name="Cluster Type A", - description="Cluster Type description", - tags=["tag 1", "tag 2"], - ), - group=ClusterGroup( - name="Cluster Group", - description="Cluster Group description", - tags=["tag 1", "tag 2"], - ), - site=Site( - name="Site ABC", - status="active", - facility="Data Center 1", - time_zone="UTC", - description="Site A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - description="Cluster A description", - tags=["tag 1", "tag 2"], - ), - site=Site( - name="Site ABC", - status="active", - facility="Data Center 1", - time_zone="UTC", - description="Site A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - role=Role(name="Role ABC", tags=["tag 1", "tag 3"]), - device=Device( - name="Device A", - device_type=DeviceType( - model="Device Type A", - manufacturer=Manufacturer(name="Manufacturer A"), - ), - platform=Platform( - name="Platform A", manufacturer=Manufacturer(name="Manufacturer A") - ), - site=Site(name="Site ABC"), - role=Role(name="Role ABC", tags=["tag 1", "tag 3"]), - serial="123456", - asset_tag="123456", - status="active", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - platform=Platform( - name="Platform A", manufacturer=Manufacturer(name="Manufacturer A") - ), - vcpus=8, - memory=12128, - disk=16786, - description="Virtual Machine A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(virtual_machine=virtual_machine_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## Virtual Disk - -Attributes: - -* `name` (str) - virtual disk name -* `virtual_machine` (str, [VirtualMachine](#virtual-machine)) - virtual machine name or VirtualMachine entity -* `size` (int) - disk size -* `description` (str) - description -* `tags` (list) - tags - -### Example -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - VirtualDisk, - VirtualMachine, - Cluster, - ClusterGroup, - ClusterType, - Device, - DeviceType, - Manufacturer, - Platform, - Role, - Site, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - VirtualDisk entity with only a name provided will attempt to create or update a name - with the given name and placeholders (i.e. "undefined") for other nested objects types (e.g. - VirtualMachine) required by NetBox. - """ - - virtual_disk = VirtualDisk(name="Disk A", size=16480) - - entities.append(Entity(virtual_disk=virtual_disk)) - - """ - VirtualDisk entity using flat data structure. - """ - - virtual_disk_flat = VirtualDisk( - name="Disk A", - virtual_machine="VM A", - size=16480, - description="Disk A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(virtual_disk=virtual_disk_flat)) - - """ - VirtualDisk entity using explicit data structure. - """ - - virtual_disk_explicit = VirtualDisk( - name="Disk A", - virtual_machine=VirtualMachine( - name="VM A", - status="active", - cluster=Cluster( - name="Cluster A", - type=ClusterType( - name="Cluster Type A", - description="Cluster Type description", - tags=["tag 1", "tag 2"], - ), - group=ClusterGroup( - name="Cluster Group", - description="Cluster Group description", - tags=["tag 1", "tag 2"], - ), - site=Site( - name="Site ABC", - status="active", - facility="Data Center 1", - time_zone="UTC", - description="Site A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - description="Cluster A description", - tags=["tag 1", "tag 2"], - ), - site=Site( - name="Site ABC", - status="active", - facility="Data Center 1", - time_zone="UTC", - description="Site A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - role=Role(name="Role ABC", tags=["tag 1", "tag 3"]), - device=Device( - name="Device A", - device_type=DeviceType( - model="Device Type A", - manufacturer=Manufacturer(name="Manufacturer A"), - ), - platform=Platform( - name="Platform A", - manufacturer=Manufacturer(name="Manufacturer A"), - ), - site=Site(name="Site ABC"), - role=Role(name="Role ABC", tags=["tag 1", "tag 3"]), - serial="123456", - asset_tag="123456", - status="active", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - platform=Platform( - name="Platform A", manufacturer=Manufacturer(name="Manufacturer A") - ), - vcpus=8, - memory=12128, - disk=16480, - description="Virtual Machine A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - size=16480, - description="Disk A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(virtual_disk=virtual_disk_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` - -## VM Interface - -Attributes: - -* `name` (str) - virtual interface name -* `virtual_machine` (str, [VirtualMachine](#virtual-machine)) - virtual machine name or VirtualMachine entity -* `enabled` (bool) - is the interface enabled -* `mtu` (int) - maximum transmission unit -* `mac_address` (str) - MAC address -* `description` (str) - description -* `tags` (list) - tags - -### Example - -```python -from netboxlabs.diode.sdk import DiodeClient -from netboxlabs.diode.sdk.ingester import ( - Entity, - VMInterface, - VirtualMachine, - Cluster, - ClusterGroup, - ClusterType, - Device, - DeviceType, - Manufacturer, - Platform, - Role, - Site, -) - - -def main(): - with DiodeClient( - target="grpc://localhost:8080/diode", - app_name="my-test-app", - app_version="0.0.1", - ) as client: - entities = [] - - """ - VMInterface entity with only a name provided will attempt to create or update a name - with the given name and placeholders (i.e. "undefined") for other nested objects types (e.g. - VirtualMachine) required by NetBox. - """ - - vminterface = VMInterface(name="Interface A") - - entities.append(Entity(vminterface=vminterface)) - - """ - VMInterface entity using flat data structure. - """ - - vminterface_flat = VMInterface( - name="Interface A", - virtual_machine="VM A", - enabled=True, - mtu=1500, - mac_address="00:00:00:00:00:00", - description="Interface A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(vminterface=vminterface_flat)) - - """ - VMInterface entity using explicit data structure. - """ - - vminterface_explicit = VMInterface( - name="Interface A", - virtual_machine=VirtualMachine( - name="VM A", - status="active", - cluster=Cluster( - name="Cluster A", - type=ClusterType( - name="Cluster Type A", - description="Cluster Type description", - tags=["tag 1", "tag 2"], - ), - group=ClusterGroup( - name="Cluster Group", - description="Cluster Group description", - tags=["tag 1", "tag 2"], - ), - site=Site( - name="Site ABC", - status="active", - facility="Data Center 1", - time_zone="UTC", - description="Site A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - description="Cluster A description", - tags=["tag 1", "tag 2"], - ), - site=Site( - name="Site ABC", - status="active", - facility="Data Center 1", - time_zone="UTC", - description="Site A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - role=Role(name="Role ABC", tags=["tag 1", "tag 3"]), - device=Device( - name="Device A", - device_type=DeviceType( - model="Device Type A", - manufacturer=Manufacturer(name="Manufacturer A"), - ), - platform=Platform( - name="Platform A", - manufacturer=Manufacturer(name="Manufacturer A"), - ), - site=Site(name="Site ABC"), - role=Role(name="Role ABC", tags=["tag 1", "tag 3"]), - serial="123456", - asset_tag="123456", - status="active", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - platform=Platform( - name="Platform A", manufacturer=Manufacturer(name="Manufacturer A") - ), - vcpus=8, - memory=12128, - disk=16480, - description="Virtual Machine A description", - comments="Lorem ipsum dolor sit amet", - tags=["tag 1", "tag 2"], - ), - enabled=True, - mtu=1500, - mac_address="00:00:00:00:00:00", - description="Interface A description", - tags=["tag 1", "tag 2"], - ) - - entities.append(Entity(vminterface=vminterface_explicit)) - - response = client.ingest(entities=entities) - if response.errors: - print(f"Errors: {response.errors}") - - -if __name__ == "__main__": - main() - -``` \ No newline at end of file +See updated docs in [README](README.md) diff --git a/docs/examples/aggregate.py b/docs/examples/aggregate.py new file mode 100644 index 0000000..0b79abd --- /dev/null +++ b/docs/examples/aggregate.py @@ -0,0 +1,97 @@ +""" +Aggregate entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Aggregate entities: +- aggregate_minimal: Required fields only +- aggregate_extended: Common optional fields +- aggregate_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Aggregate, + Entity, + Owner, + OwnerGroup, + RIR, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "aggregate-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Aggregate entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + aggregate = aggregate_minimal() + # aggregate = aggregate_extended() + # aggregate = aggregate_explicit() + + response = client.ingest(entities=[Entity(aggregate=aggregate)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Aggregate ingested successfully") + + +def aggregate_minimal() -> Aggregate: + """Create a Aggregate with only required fields using flat strings.""" + return Aggregate( + prefix="192.0.2.0/24", + rir="Example RIR", # flat string -> RIR + metadata={"source": "example"}, + ) + + +def aggregate_extended() -> Aggregate: + """Create a Aggregate with common optional fields.""" + return Aggregate( + prefix="192.0.2.0/24", + rir="Example RIR", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + tenant="Example Tenant", + comments="Example comments", + ) + + +def aggregate_explicit() -> Aggregate: + """Create a Aggregate with fully nested objects and all common fields.""" + return Aggregate( + prefix="192.0.2.0/24", + rir=RIR( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/asn.py b/docs/examples/asn.py new file mode 100644 index 0000000..fa0eb5b --- /dev/null +++ b/docs/examples/asn.py @@ -0,0 +1,96 @@ +""" +ASN entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ASN entities: +- asn_minimal: Required fields only +- asn_extended: Common optional fields +- asn_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + ASN, + Entity, + Owner, + OwnerGroup, + RIR, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "asn-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ASN entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + asn = asn_minimal() + # asn = asn_extended() + # asn = asn_explicit() + + response = client.ingest(entities=[Entity(asn=asn)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ASN ingested successfully") + + +def asn_minimal() -> ASN: + """Create a ASN with only required fields using flat strings.""" + return ASN( + asn=64512, + metadata={"source": "example"}, + ) + + +def asn_extended() -> ASN: + """Create a ASN with common optional fields.""" + return ASN( + asn=64512, + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + rir="Example RIR", + tenant="Example Tenant", + comments="Example comments", + ) + + +def asn_explicit() -> ASN: + """Create a ASN with fully nested objects and all common fields.""" + return ASN( + asn=64512, + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + rir=RIR( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/asn_range.py b/docs/examples/asn_range.py new file mode 100644 index 0000000..bc84b30 --- /dev/null +++ b/docs/examples/asn_range.py @@ -0,0 +1,106 @@ +""" +ASNRange entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ASNRange entities: +- asn_range_minimal: Required fields only +- asn_range_extended: Common optional fields +- asn_range_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + ASNRange, + Entity, + Owner, + OwnerGroup, + RIR, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "asn_range-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ASNRange entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + asn_range = asn_range_minimal() + # asn_range = asn_range_extended() + # asn_range = asn_range_explicit() + + response = client.ingest(entities=[Entity(asn_range=asn_range)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ASNRange ingested successfully") + + +def asn_range_minimal() -> ASNRange: + """Create a ASNRange with only required fields using flat strings.""" + return ASNRange( + name="Example Name", + slug="example-slug", + rir="Example RIR", # flat string -> RIR + start=1, + end=1, + metadata={"source": "example"}, + ) + + +def asn_range_extended() -> ASNRange: + """Create a ASNRange with common optional fields.""" + return ASNRange( + name="Example Name", + slug="example-slug", + rir="Example RIR", + start=1, + end=1, + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + tenant="Example Tenant", + comments="Example comments", + ) + + +def asn_range_explicit() -> ASNRange: + """Create a ASNRange with fully nested objects and all common fields.""" + return ASNRange( + name="Example Name", + slug="example-slug", + rir=RIR( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + start=1, + end=1, + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/cable.py b/docs/examples/cable.py new file mode 100644 index 0000000..a11ecd5 --- /dev/null +++ b/docs/examples/cable.py @@ -0,0 +1,102 @@ +""" +Cable entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Cable entities: +- cable_minimal: Required fields only +- cable_extended: Common optional fields +- cable_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Cable, + Entity, + Owner, + OwnerGroup, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "cable-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Cable entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + cable = cable_minimal() + # cable = cable_extended() + # cable = cable_explicit() + + response = client.ingest(entities=[Entity(cable=cable)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Cable ingested successfully") + + +def cable_minimal() -> Cable: + """Create a Cable with only required fields using flat strings.""" + return Cable( + metadata={"source": "example"}, + ) + + +def cable_extended() -> Cable: + """Create a Cable with common optional fields.""" + return Cable( + metadata={"source": "example", "custom_key": "custom_value"}, + status="connected", + description="Example description", + color="0000ff", + type="aoc", + tenant="Example Tenant", + label="Example Label", + length=1.0, + length_unit="cm", + comments="Example comments", + profile="breakout-1c4p-4c1p", + ) + + +def cable_explicit() -> Cable: + """Create a Cable with fully nested objects and all common fields.""" + return Cable( + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="connected", + description="Example description", + color="0000ff", + comments="Example comments", + type="aoc", + label="Example Label", + length=1.0, + length_unit="cm", + profile="breakout-1c4p-4c1p", + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/cable_path.py b/docs/examples/cable_path.py new file mode 100644 index 0000000..30fa92b --- /dev/null +++ b/docs/examples/cable_path.py @@ -0,0 +1,72 @@ +""" +CablePath entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting CablePath entities: +- cable_path_minimal: Required fields only +- cable_path_extended: Common optional fields +- cable_path_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "cable_path-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a CablePath entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + cable_path = cable_path_minimal() + # cable_path = cable_path_extended() + # cable_path = cable_path_explicit() + + response = client.ingest(entities=[Entity(cable_path=cable_path)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("CablePath ingested successfully") + + +def cable_path_minimal() -> CablePath: + """Create a CablePath with only required fields using flat strings.""" + return CablePath( + metadata={"source": "example"}, + ) + + +def cable_path_extended() -> CablePath: + """Create a CablePath with common optional fields.""" + return CablePath( + metadata={"source": "example", "custom_key": "custom_value"}, + is_active=True, + is_complete=True, + is_split=True, + ) + + +def cable_path_explicit() -> CablePath: + """Create a CablePath with fully nested objects and all common fields.""" + return CablePath( + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + is_active=True, + is_complete=True, + is_split=True, + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/cable_termination.py b/docs/examples/cable_termination.py new file mode 100644 index 0000000..d0b44a0 --- /dev/null +++ b/docs/examples/cable_termination.py @@ -0,0 +1,77 @@ +""" +CableTermination entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting CableTermination entities: +- cable_termination_minimal: Required fields only +- cable_termination_extended: Common optional fields +- cable_termination_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Cable, + CableTermination, + Entity, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "cable_termination-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a CableTermination entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + cable_termination = cable_termination_minimal() + # cable_termination = cable_termination_extended() + # cable_termination = cable_termination_explicit() + + response = client.ingest(entities=[Entity(cable_termination=cable_termination)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("CableTermination ingested successfully") + + +def cable_termination_minimal() -> CableTermination: + """Create a CableTermination with only required fields using flat strings.""" + return CableTermination( + cable="Example Cable", # flat string -> Cable + cable_end="A", + metadata={"source": "example"}, + ) + + +def cable_termination_extended() -> CableTermination: + """Create a CableTermination with common optional fields.""" + return CableTermination( + cable="Example Cable", + cable_end="A", + metadata={"source": "example", "custom_key": "custom_value"}, + ) + + +def cable_termination_explicit() -> CableTermination: + """Create a CableTermination with fully nested objects and all common fields.""" + return CableTermination( + cable=Cable(status="active", color="0000ff", metadata={"source": "example"}), + cable_end="A", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/circuit.py b/docs/examples/circuit.py new file mode 100644 index 0000000..1ce975f --- /dev/null +++ b/docs/examples/circuit.py @@ -0,0 +1,122 @@ +""" +Circuit entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Circuit entities: +- circuit_minimal: Required fields only +- circuit_extended: Common optional fields +- circuit_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Circuit, + CircuitType, + Entity, + Owner, + OwnerGroup, + Provider, + ProviderAccount, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "circuit-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Circuit entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + circuit = circuit_minimal() + # circuit = circuit_extended() + # circuit = circuit_explicit() + + response = client.ingest(entities=[Entity(circuit=circuit)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Circuit ingested successfully") + + +def circuit_minimal() -> Circuit: + """Create a Circuit with only required fields using flat strings.""" + return Circuit( + cid="CID-001", + provider="Example Provider", # flat string -> Provider + type="Example Type", # flat string -> CircuitType + metadata={"source": "example"}, + ) + + +def circuit_extended() -> Circuit: + """Create a Circuit with common optional fields.""" + return Circuit( + cid="CID-001", + provider="Example Provider", + type="Example Type", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + tenant="Example Tenant", + commit_rate=1, + distance=1.0, + distance_unit="ft", + comments="Example comments", + ) + + +def circuit_explicit() -> Circuit: + """Create a Circuit with fully nested objects and all common fields.""" + return Circuit( + cid="CID-001", + provider=Provider( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + type=CircuitType( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + commit_rate=1, + distance=1.0, + distance_unit="ft", + provider_account=ProviderAccount( + provider=Provider( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + account="Example Account", + metadata={"source": "example"}, + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/circuit_group.py b/docs/examples/circuit_group.py new file mode 100644 index 0000000..cd68c8e --- /dev/null +++ b/docs/examples/circuit_group.py @@ -0,0 +1,94 @@ +""" +CircuitGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting CircuitGroup entities: +- circuit_group_minimal: Required fields only +- circuit_group_extended: Common optional fields +- circuit_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + CircuitGroup, + Entity, + Owner, + OwnerGroup, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "circuit_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a CircuitGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + circuit_group = circuit_group_minimal() + # circuit_group = circuit_group_extended() + # circuit_group = circuit_group_explicit() + + response = client.ingest(entities=[Entity(circuit_group=circuit_group)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("CircuitGroup ingested successfully") + + +def circuit_group_minimal() -> CircuitGroup: + """Create a CircuitGroup with only required fields using flat strings.""" + return CircuitGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def circuit_group_extended() -> CircuitGroup: + """Create a CircuitGroup with common optional fields.""" + return CircuitGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + tenant="Example Tenant", + comments="Example comments", + ) + + +def circuit_group_explicit() -> CircuitGroup: + """Create a CircuitGroup with fully nested objects and all common fields.""" + return CircuitGroup( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/circuit_group_assignment.py b/docs/examples/circuit_group_assignment.py new file mode 100644 index 0000000..3272774 --- /dev/null +++ b/docs/examples/circuit_group_assignment.py @@ -0,0 +1,82 @@ +""" +CircuitGroupAssignment entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting CircuitGroupAssignment entities: +- circuit_group_assignment_minimal: Required fields only +- circuit_group_assignment_extended: Common optional fields +- circuit_group_assignment_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + CircuitGroup, + CircuitGroupAssignment, + Entity, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "circuit_group_assignment-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a CircuitGroupAssignment entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + circuit_group_assignment = circuit_group_assignment_minimal() + # circuit_group_assignment = circuit_group_assignment_extended() + # circuit_group_assignment = circuit_group_assignment_explicit() + + response = client.ingest( + entities=[Entity(circuit_group_assignment=circuit_group_assignment)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("CircuitGroupAssignment ingested successfully") + + +def circuit_group_assignment_minimal() -> CircuitGroupAssignment: + """Create a CircuitGroupAssignment with only required fields using flat strings.""" + return CircuitGroupAssignment( + group="Example Group", # flat string -> CircuitGroup + metadata={"source": "example"}, + ) + + +def circuit_group_assignment_extended() -> CircuitGroupAssignment: + """Create a CircuitGroupAssignment with common optional fields.""" + return CircuitGroupAssignment( + group="Example Group", + metadata={"source": "example", "custom_key": "custom_value"}, + priority="inactive", + ) + + +def circuit_group_assignment_explicit() -> CircuitGroupAssignment: + """Create a CircuitGroupAssignment with fully nested objects and all common fields.""" + return CircuitGroupAssignment( + group=CircuitGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + priority="inactive", + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/circuit_termination.py b/docs/examples/circuit_termination.py new file mode 100644 index 0000000..7d655d6 --- /dev/null +++ b/docs/examples/circuit_termination.py @@ -0,0 +1,108 @@ +""" +CircuitTermination entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting CircuitTermination entities: +- circuit_termination_minimal: Required fields only +- circuit_termination_extended: Common optional fields +- circuit_termination_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Circuit, + CircuitTermination, + CircuitType, + Entity, + Provider, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "circuit_termination-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a CircuitTermination entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + circuit_termination = circuit_termination_minimal() + # circuit_termination = circuit_termination_extended() + # circuit_termination = circuit_termination_explicit() + + response = client.ingest( + entities=[Entity(circuit_termination=circuit_termination)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("CircuitTermination ingested successfully") + + +def circuit_termination_minimal() -> CircuitTermination: + """Create a CircuitTermination with only required fields using flat strings.""" + return CircuitTermination( + circuit="Example Circuit", # flat string -> Circuit + term_side="A", + metadata={"source": "example"}, + ) + + +def circuit_termination_extended() -> CircuitTermination: + """Create a CircuitTermination with common optional fields.""" + return CircuitTermination( + circuit="Example Circuit", + term_side="A", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + port_speed=1, + upstream_speed=1, + xconnect_id="Example Xconnect Id", + pp_info="Example Pp Info", + mark_connected=True, + ) + + +def circuit_termination_explicit() -> CircuitTermination: + """Create a CircuitTermination with fully nested objects and all common fields.""" + return CircuitTermination( + circuit=Circuit( + cid="CID-001", + provider=Provider( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + type=CircuitType( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + term_side="A", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + port_speed=1, + upstream_speed=1, + xconnect_id="Example Xconnect Id", + pp_info="Example Pp Info", + mark_connected=True, + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/circuit_type.py b/docs/examples/circuit_type.py new file mode 100644 index 0000000..b824b81 --- /dev/null +++ b/docs/examples/circuit_type.py @@ -0,0 +1,91 @@ +""" +CircuitType entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting CircuitType entities: +- circuit_type_minimal: Required fields only +- circuit_type_extended: Common optional fields +- circuit_type_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + CircuitType, + Entity, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "circuit_type-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a CircuitType entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + circuit_type = circuit_type_minimal() + # circuit_type = circuit_type_extended() + # circuit_type = circuit_type_explicit() + + response = client.ingest(entities=[Entity(circuit_type=circuit_type)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("CircuitType ingested successfully") + + +def circuit_type_minimal() -> CircuitType: + """Create a CircuitType with only required fields using flat strings.""" + return CircuitType( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def circuit_type_extended() -> CircuitType: + """Create a CircuitType with common optional fields.""" + return CircuitType( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + color="0000ff", + comments="Example comments", + ) + + +def circuit_type_explicit() -> CircuitType: + """Create a CircuitType with fully nested objects and all common fields.""" + return CircuitType( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + color="0000ff", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/cluster.py b/docs/examples/cluster.py new file mode 100644 index 0000000..777c294 --- /dev/null +++ b/docs/examples/cluster.py @@ -0,0 +1,103 @@ +""" +Cluster entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Cluster entities: +- cluster_minimal: Required fields only +- cluster_extended: Common optional fields +- cluster_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Cluster, + ClusterGroup, + ClusterType, + Entity, + Owner, + OwnerGroup, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "cluster-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Cluster entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + cluster = cluster_minimal() + # cluster = cluster_extended() + # cluster = cluster_explicit() + + response = client.ingest(entities=[Entity(cluster=cluster)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Cluster ingested successfully") + + +def cluster_minimal() -> Cluster: + """Create a Cluster with only required fields using flat strings.""" + return Cluster( + name="Example Name", + type="Example Type", # flat string -> ClusterType + metadata={"source": "example"}, + ) + + +def cluster_extended() -> Cluster: + """Create a Cluster with common optional fields.""" + return Cluster( + name="Example Name", + type="Example Type", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + tenant="Example Tenant", + comments="Example comments", + ) + + +def cluster_explicit() -> Cluster: + """Create a Cluster with fully nested objects and all common fields.""" + return Cluster( + name="Example Name", + type=ClusterType( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + group=ClusterGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/cluster_group.py b/docs/examples/cluster_group.py new file mode 100644 index 0000000..26b651a --- /dev/null +++ b/docs/examples/cluster_group.py @@ -0,0 +1,89 @@ +""" +ClusterGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ClusterGroup entities: +- cluster_group_minimal: Required fields only +- cluster_group_extended: Common optional fields +- cluster_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + ClusterGroup, + Entity, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "cluster_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ClusterGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + cluster_group = cluster_group_minimal() + # cluster_group = cluster_group_extended() + # cluster_group = cluster_group_explicit() + + response = client.ingest(entities=[Entity(cluster_group=cluster_group)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ClusterGroup ingested successfully") + + +def cluster_group_minimal() -> ClusterGroup: + """Create a ClusterGroup with only required fields using flat strings.""" + return ClusterGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def cluster_group_extended() -> ClusterGroup: + """Create a ClusterGroup with common optional fields.""" + return ClusterGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def cluster_group_explicit() -> ClusterGroup: + """Create a ClusterGroup with fully nested objects and all common fields.""" + return ClusterGroup( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/cluster_type.py b/docs/examples/cluster_type.py new file mode 100644 index 0000000..cc2271d --- /dev/null +++ b/docs/examples/cluster_type.py @@ -0,0 +1,89 @@ +""" +ClusterType entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ClusterType entities: +- cluster_type_minimal: Required fields only +- cluster_type_extended: Common optional fields +- cluster_type_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + ClusterType, + Entity, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "cluster_type-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ClusterType entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + cluster_type = cluster_type_minimal() + # cluster_type = cluster_type_extended() + # cluster_type = cluster_type_explicit() + + response = client.ingest(entities=[Entity(cluster_type=cluster_type)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ClusterType ingested successfully") + + +def cluster_type_minimal() -> ClusterType: + """Create a ClusterType with only required fields using flat strings.""" + return ClusterType( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def cluster_type_extended() -> ClusterType: + """Create a ClusterType with common optional fields.""" + return ClusterType( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def cluster_type_explicit() -> ClusterType: + """Create a ClusterType with fully nested objects and all common fields.""" + return ClusterType( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/console_port.py b/docs/examples/console_port.py new file mode 100644 index 0000000..a0d0b68 --- /dev/null +++ b/docs/examples/console_port.py @@ -0,0 +1,197 @@ +""" +ConsolePort entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ConsolePort entities: +- console_port_minimal: Required fields only +- console_port_extended: Common optional fields +- console_port_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + ConsolePort, + Device, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Module, + ModuleBay, + ModuleType, + Owner, + OwnerGroup, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "console_port-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ConsolePort entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + console_port = console_port_minimal() + # console_port = console_port_extended() + # console_port = console_port_explicit() + + response = client.ingest(entities=[Entity(console_port=console_port)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ConsolePort ingested successfully") + + +def console_port_minimal() -> ConsolePort: + """Create a ConsolePort with only required fields using flat strings.""" + return ConsolePort( + device="Example Device", # flat string -> Device + name="Example Name", + metadata={"source": "example"}, + ) + + +def console_port_extended() -> ConsolePort: + """Create a ConsolePort with common optional fields.""" + return ConsolePort( + device="Example Device", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + label="Example Label", + type="db-25", + speed=1, + mark_connected=True, + ) + + +def console_port_explicit() -> ConsolePort: + """Create a ConsolePort with fully nested objects and all common fields.""" + return ConsolePort( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + label="Example Label", + type="db-25", + speed=1, + mark_connected=True, + module=Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/console_server_port.py b/docs/examples/console_server_port.py new file mode 100644 index 0000000..dda1700 --- /dev/null +++ b/docs/examples/console_server_port.py @@ -0,0 +1,199 @@ +""" +ConsoleServerPort entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ConsoleServerPort entities: +- console_server_port_minimal: Required fields only +- console_server_port_extended: Common optional fields +- console_server_port_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + ConsoleServerPort, + Device, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Module, + ModuleBay, + ModuleType, + Owner, + OwnerGroup, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "console_server_port-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ConsoleServerPort entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + console_server_port = console_server_port_minimal() + # console_server_port = console_server_port_extended() + # console_server_port = console_server_port_explicit() + + response = client.ingest( + entities=[Entity(console_server_port=console_server_port)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ConsoleServerPort ingested successfully") + + +def console_server_port_minimal() -> ConsoleServerPort: + """Create a ConsoleServerPort with only required fields using flat strings.""" + return ConsoleServerPort( + device="Example Device", # flat string -> Device + name="Example Name", + metadata={"source": "example"}, + ) + + +def console_server_port_extended() -> ConsoleServerPort: + """Create a ConsoleServerPort with common optional fields.""" + return ConsoleServerPort( + device="Example Device", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + label="Example Label", + type="db-25", + speed=1, + mark_connected=True, + ) + + +def console_server_port_explicit() -> ConsoleServerPort: + """Create a ConsoleServerPort with fully nested objects and all common fields.""" + return ConsoleServerPort( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + label="Example Label", + type="db-25", + speed=1, + mark_connected=True, + module=Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/contact.py b/docs/examples/contact.py new file mode 100644 index 0000000..20afd5a --- /dev/null +++ b/docs/examples/contact.py @@ -0,0 +1,100 @@ +""" +Contact entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Contact entities: +- contact_minimal: Required fields only +- contact_extended: Common optional fields +- contact_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Contact, + ContactGroup, + Entity, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "contact-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Contact entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + contact = contact_minimal() + # contact = contact_extended() + # contact = contact_explicit() + + response = client.ingest(entities=[Entity(contact=contact)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Contact ingested successfully") + + +def contact_minimal() -> Contact: + """Create a Contact with only required fields using flat strings.""" + return Contact( + name="Example Name", + metadata={"source": "example"}, + ) + + +def contact_extended() -> Contact: + """Create a Contact with common optional fields.""" + return Contact( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + title="Example Title", + phone="Example Phone", + email="Example Email", + address="192.0.2.1/32", + link="Example Link", + comments="Example comments", + ) + + +def contact_explicit() -> Contact: + """Create a Contact with fully nested objects and all common fields.""" + return Contact( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + title="Example Title", + phone="Example Phone", + email="Example Email", + address="192.0.2.1/32", + link="Example Link", + group=ContactGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/contact_assignment.py b/docs/examples/contact_assignment.py new file mode 100644 index 0000000..b85c277 --- /dev/null +++ b/docs/examples/contact_assignment.py @@ -0,0 +1,85 @@ +""" +ContactAssignment entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ContactAssignment entities: +- contact_assignment_minimal: Required fields only +- contact_assignment_extended: Common optional fields +- contact_assignment_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Contact, + ContactAssignment, + ContactRole, + Entity, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "contact_assignment-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ContactAssignment entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + contact_assignment = contact_assignment_minimal() + # contact_assignment = contact_assignment_extended() + # contact_assignment = contact_assignment_explicit() + + response = client.ingest( + entities=[Entity(contact_assignment=contact_assignment)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ContactAssignment ingested successfully") + + +def contact_assignment_minimal() -> ContactAssignment: + """Create a ContactAssignment with only required fields using flat strings.""" + return ContactAssignment( + contact="Example Contact", # flat string -> Contact + metadata={"source": "example"}, + ) + + +def contact_assignment_extended() -> ContactAssignment: + """Create a ContactAssignment with common optional fields.""" + return ContactAssignment( + contact="Example Contact", + metadata={"source": "example", "custom_key": "custom_value"}, + role="Example Role", + priority="inactive", + ) + + +def contact_assignment_explicit() -> ContactAssignment: + """Create a ContactAssignment with fully nested objects and all common fields.""" + return ContactAssignment( + contact=Contact(name="Example Name", metadata={"source": "example"}), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + priority="inactive", + role=ContactRole( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/contact_group.py b/docs/examples/contact_group.py new file mode 100644 index 0000000..393127e --- /dev/null +++ b/docs/examples/contact_group.py @@ -0,0 +1,92 @@ +""" +ContactGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ContactGroup entities: +- contact_group_minimal: Required fields only +- contact_group_extended: Common optional fields +- contact_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + ContactGroup, + Entity, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "contact_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ContactGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + contact_group = contact_group_minimal() + # contact_group = contact_group_extended() + # contact_group = contact_group_explicit() + + response = client.ingest(entities=[Entity(contact_group=contact_group)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ContactGroup ingested successfully") + + +def contact_group_minimal() -> ContactGroup: + """Create a ContactGroup with only required fields using flat strings.""" + return ContactGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def contact_group_extended() -> ContactGroup: + """Create a ContactGroup with common optional fields.""" + return ContactGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def contact_group_explicit() -> ContactGroup: + """Create a ContactGroup with fully nested objects and all common fields.""" + return ContactGroup( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + parent=ContactGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/contact_role.py b/docs/examples/contact_role.py new file mode 100644 index 0000000..41a8bce --- /dev/null +++ b/docs/examples/contact_role.py @@ -0,0 +1,89 @@ +""" +ContactRole entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ContactRole entities: +- contact_role_minimal: Required fields only +- contact_role_extended: Common optional fields +- contact_role_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + ContactRole, + Entity, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "contact_role-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ContactRole entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + contact_role = contact_role_minimal() + # contact_role = contact_role_extended() + # contact_role = contact_role_explicit() + + response = client.ingest(entities=[Entity(contact_role=contact_role)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ContactRole ingested successfully") + + +def contact_role_minimal() -> ContactRole: + """Create a ContactRole with only required fields using flat strings.""" + return ContactRole( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def contact_role_extended() -> ContactRole: + """Create a ContactRole with common optional fields.""" + return ContactRole( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def contact_role_explicit() -> ContactRole: + """Create a ContactRole with fully nested objects and all common fields.""" + return ContactRole( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/custom_field.py b/docs/examples/custom_field.py new file mode 100644 index 0000000..31a19cd --- /dev/null +++ b/docs/examples/custom_field.py @@ -0,0 +1,123 @@ +""" +CustomField entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting CustomField entities: +- custom_field_minimal: Required fields only +- custom_field_extended: Common optional fields +- custom_field_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + CustomField, + CustomFieldChoiceSet, + Entity, + Owner, + OwnerGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "custom_field-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a CustomField entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + custom_field = custom_field_minimal() + # custom_field = custom_field_extended() + # custom_field = custom_field_explicit() + + response = client.ingest(entities=[Entity(custom_field=custom_field)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("CustomField ingested successfully") + + +def custom_field_minimal() -> CustomField: + """Create a CustomField with only required fields using flat strings.""" + return CustomField( + type="boolean", + name="Example Name", + metadata={"source": "example"}, + ) + + +def custom_field_extended() -> CustomField: + """Create a CustomField with common optional fields.""" + return CustomField( + type="boolean", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + related_object_type="circuits.circuit", + label="Example Label", + group_name="Example Group Name", + required=True, + unique=True, + search_weight=1, + filter_logic="disabled", + ui_visible="always", + ui_editable="hidden", + is_cloneable=True, + default="Example Default", + related_object_filter="Example Related Object Filter", + weight=1, + validation_minimum=1.0, + validation_maximum=1.0, + validation_regex="Example Validation Regex", + comments="Example comments", + ) + + +def custom_field_explicit() -> CustomField: + """Create a CustomField with fully nested objects and all common fields.""" + return CustomField( + type="boolean", + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + related_object_type="circuits.circuit", + label="Example Label", + group_name="Example Group Name", + required=True, + unique=True, + search_weight=1, + filter_logic="disabled", + ui_visible="always", + ui_editable="hidden", + is_cloneable=True, + default="Example Default", + related_object_filter="Example Related Object Filter", + weight=1, + validation_minimum=1.0, + validation_maximum=1.0, + validation_regex="Example Validation Regex", + choice_set=CustomFieldChoiceSet( + name="Example Name", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/custom_field_choice_set.py b/docs/examples/custom_field_choice_set.py new file mode 100644 index 0000000..5686986 --- /dev/null +++ b/docs/examples/custom_field_choice_set.py @@ -0,0 +1,88 @@ +""" +CustomFieldChoiceSet entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting CustomFieldChoiceSet entities: +- custom_field_choice_set_minimal: Required fields only +- custom_field_choice_set_extended: Common optional fields +- custom_field_choice_set_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + CustomFieldChoiceSet, + Entity, + Owner, + OwnerGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "custom_field_choice_set-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a CustomFieldChoiceSet entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + custom_field_choice_set = custom_field_choice_set_minimal() + # custom_field_choice_set = custom_field_choice_set_extended() + # custom_field_choice_set = custom_field_choice_set_explicit() + + response = client.ingest( + entities=[Entity(custom_field_choice_set=custom_field_choice_set)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("CustomFieldChoiceSet ingested successfully") + + +def custom_field_choice_set_minimal() -> CustomFieldChoiceSet: + """Create a CustomFieldChoiceSet with only required fields using flat strings.""" + return CustomFieldChoiceSet( + name="Example Name", + metadata={"source": "example"}, + ) + + +def custom_field_choice_set_extended() -> CustomFieldChoiceSet: + """Create a CustomFieldChoiceSet with common optional fields.""" + return CustomFieldChoiceSet( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + base_choices="IATA", + order_alphabetically=True, + ) + + +def custom_field_choice_set_explicit() -> CustomFieldChoiceSet: + """Create a CustomFieldChoiceSet with fully nested objects and all common fields.""" + return CustomFieldChoiceSet( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + base_choices="IATA", + order_alphabetically=True, + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/custom_link.py b/docs/examples/custom_link.py new file mode 100644 index 0000000..964e947 --- /dev/null +++ b/docs/examples/custom_link.py @@ -0,0 +1,96 @@ +""" +CustomLink entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting CustomLink entities: +- custom_link_minimal: Required fields only +- custom_link_extended: Common optional fields +- custom_link_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + CustomLink, + Entity, + Owner, + OwnerGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "custom_link-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a CustomLink entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + custom_link = custom_link_minimal() + # custom_link = custom_link_extended() + # custom_link = custom_link_explicit() + + response = client.ingest(entities=[Entity(custom_link=custom_link)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("CustomLink ingested successfully") + + +def custom_link_minimal() -> CustomLink: + """Create a CustomLink with only required fields using flat strings.""" + return CustomLink( + name="Example Name", + link_text="Example Link Text", + link_url="Example Link Url", + metadata={"source": "example"}, + ) + + +def custom_link_extended() -> CustomLink: + """Create a CustomLink with common optional fields.""" + return CustomLink( + name="Example Name", + link_text="Example Link Text", + link_url="Example Link Url", + metadata={"source": "example", "custom_key": "custom_value"}, + enabled=True, + weight=1, + group_name="Example Group Name", + button_class="black", + new_window=True, + ) + + +def custom_link_explicit() -> CustomLink: + """Create a CustomLink with fully nested objects and all common fields.""" + return CustomLink( + name="Example Name", + link_text="Example Link Text", + link_url="Example Link Url", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + enabled=True, + weight=1, + group_name="Example Group Name", + button_class="black", + new_window=True, + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/device.py b/docs/examples/device.py new file mode 100644 index 0000000..93934bb --- /dev/null +++ b/docs/examples/device.py @@ -0,0 +1,204 @@ +""" +Device entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Device entities: +- device_minimal: Required fields only +- device_extended: Common optional fields +- device_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Cluster, + ClusterType, + Device, + DeviceConfig, + DeviceRole, + DeviceType, + Entity, + IPAddress, + Location, + Manufacturer, + Owner, + OwnerGroup, + Platform, + Rack, + Site, + Tag, + Tenant, + VirtualChassis, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "device-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Device entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + device = device_minimal() + # device = device_extended() + # device = device_explicit() + + response = client.ingest(entities=[Entity(device=device)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Device ingested successfully") + + +def device_minimal() -> Device: + """Create a Device with only required fields using flat strings.""" + return Device( + device_type="Model X", # flat string -> DeviceType + role="Example Role", # flat string -> DeviceRole + site="Example Site", # flat string -> Site + metadata={"source": "example"}, + ) + + +def device_extended() -> Device: + """Create a Device with common optional fields.""" + return Device( + device_type="Model X", + role="Example Role", + site="Example Site", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + serial="SN-001234", + description="Example description", + name="Example Name", + tenant="Example Tenant", + platform="Example Platform", + asset_tag="ASSET-001", + location="Example Location", + rack="Example Rack", + position=1.0, + face="front", + latitude=1.0, + longitude=1.0, + airflow="bottom-to-top", + cluster="Example Cluster", + vc_position=1, + vc_priority=1, + comments="Example comments", + ) + + +def device_explicit() -> Device: + """Create a Device with fully nested objects and all common fields.""" + return Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + serial="SN-001234", + description="Example description", + comments="Example comments", + asset_tag="ASSET-001", + name="Example Name", + position=1.0, + face="front", + latitude=1.0, + longitude=1.0, + airflow="bottom-to-top", + vc_position=1, + vc_priority=1, + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + platform=Platform( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + location=Location( + name="Example Name", + slug="example-slug", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + rack=Rack( + name="Example Name", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + primary_ip4=IPAddress( + address="192.0.2.1/32", status="active", metadata={"source": "example"} + ), + primary_ip6=IPAddress( + address="192.0.2.1/32", status="active", metadata={"source": "example"} + ), + oob_ip=IPAddress( + address="192.0.2.1/32", status="active", metadata={"source": "example"} + ), + cluster=Cluster( + name="Example Name", + type=ClusterType( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + status="active", + metadata={"source": "example"}, + ), + virtual_chassis=VirtualChassis( + name="Example Name", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + config=DeviceConfig( + startup=b"example data", + running=b"example data", + candidate=b"example data", + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/device_bay.py b/docs/examples/device_bay.py new file mode 100644 index 0000000..84a9260 --- /dev/null +++ b/docs/examples/device_bay.py @@ -0,0 +1,145 @@ +""" +DeviceBay entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting DeviceBay entities: +- device_bay_minimal: Required fields only +- device_bay_extended: Common optional fields +- device_bay_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceBay, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Owner, + OwnerGroup, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "device_bay-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a DeviceBay entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + device_bay = device_bay_minimal() + # device_bay = device_bay_extended() + # device_bay = device_bay_explicit() + + response = client.ingest(entities=[Entity(device_bay=device_bay)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("DeviceBay ingested successfully") + + +def device_bay_minimal() -> DeviceBay: + """Create a DeviceBay with only required fields using flat strings.""" + return DeviceBay( + device="Example Device", # flat string -> Device + name="Example Name", + metadata={"source": "example"}, + ) + + +def device_bay_extended() -> DeviceBay: + """Create a DeviceBay with common optional fields.""" + return DeviceBay( + device="Example Device", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + label="Example Label", + ) + + +def device_bay_explicit() -> DeviceBay: + """Create a DeviceBay with fully nested objects and all common fields.""" + return DeviceBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + label="Example Label", + installed_device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/device_config.py b/docs/examples/device_config.py new file mode 100644 index 0000000..3a995a4 --- /dev/null +++ b/docs/examples/device_config.py @@ -0,0 +1,72 @@ +""" +DeviceConfig entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting DeviceConfig entities: +- device_config_minimal: Required fields only +- device_config_extended: Common optional fields +- device_config_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "device_config-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a DeviceConfig entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + device_config = device_config_minimal() + # device_config = device_config_extended() + # device_config = device_config_explicit() + + response = client.ingest(entities=[Entity(device_config=device_config)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("DeviceConfig ingested successfully") + + +def device_config_minimal() -> DeviceConfig: + """Create a DeviceConfig with only required fields using flat strings.""" + return DeviceConfig( + startup=b"example data", + metadata={"source": "example"}, + ) + + +def device_config_extended() -> DeviceConfig: + """Create a DeviceConfig with common optional fields.""" + return DeviceConfig( + startup=b"example data", + running=b"example data", + metadata={"source": "example", "custom_key": "custom_value"}, + ) + + +def device_config_explicit() -> DeviceConfig: + """Create a DeviceConfig with fully nested objects and all common fields.""" + return DeviceConfig( + startup=b"example data", + running=b"example data", + candidate=b"example data", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/device_role.py b/docs/examples/device_role.py new file mode 100644 index 0000000..a265ad0 --- /dev/null +++ b/docs/examples/device_role.py @@ -0,0 +1,99 @@ +""" +DeviceRole entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting DeviceRole entities: +- device_role_minimal: Required fields only +- device_role_extended: Common optional fields +- device_role_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + DeviceRole, + Entity, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "device_role-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a DeviceRole entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + device_role = device_role_minimal() + # device_role = device_role_extended() + # device_role = device_role_explicit() + + response = client.ingest(entities=[Entity(device_role=device_role)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("DeviceRole ingested successfully") + + +def device_role_minimal() -> DeviceRole: + """Create a DeviceRole with only required fields using flat strings.""" + return DeviceRole( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def device_role_extended() -> DeviceRole: + """Create a DeviceRole with common optional fields.""" + return DeviceRole( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + color="0000ff", + vm_role=True, + comments="Example comments", + ) + + +def device_role_explicit() -> DeviceRole: + """Create a DeviceRole with fully nested objects and all common fields.""" + return DeviceRole( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + color="0000ff", + comments="Example comments", + vm_role=True, + parent=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/device_type.py b/docs/examples/device_type.py new file mode 100644 index 0000000..3d2352d --- /dev/null +++ b/docs/examples/device_type.py @@ -0,0 +1,115 @@ +""" +DeviceType entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting DeviceType entities: +- device_type_minimal: Required fields only +- device_type_extended: Common optional fields +- device_type_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + DeviceType, + Entity, + Manufacturer, + Owner, + OwnerGroup, + Platform, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "device_type-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a DeviceType entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + device_type = device_type_minimal() + # device_type = device_type_extended() + # device_type = device_type_explicit() + + response = client.ingest(entities=[Entity(device_type=device_type)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("DeviceType ingested successfully") + + +def device_type_minimal() -> DeviceType: + """Create a DeviceType with only required fields using flat strings.""" + return DeviceType( + manufacturer="Example Manufacturer", # flat string -> Manufacturer + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def device_type_extended() -> DeviceType: + """Create a DeviceType with common optional fields.""" + return DeviceType( + manufacturer="Example Manufacturer", + model="Model X", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + part_number="Example Part Number", + u_height=1.0, + exclude_from_utilization=True, + is_full_depth=True, + subdevice_role="child", + airflow="bottom-to-top", + weight=1.0, + weight_unit="g", + comments="Example comments", + ) + + +def device_type_explicit() -> DeviceType: + """Create a DeviceType with fully nested objects and all common fields.""" + return DeviceType( + manufacturer=Manufacturer( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + model="Model X", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + part_number="Example Part Number", + u_height=1.0, + exclude_from_utilization=True, + is_full_depth=True, + subdevice_role="child", + airflow="bottom-to-top", + weight=1.0, + weight_unit="g", + default_platform=Platform( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/fhrp_group.py b/docs/examples/fhrp_group.py new file mode 100644 index 0000000..4414aa8 --- /dev/null +++ b/docs/examples/fhrp_group.py @@ -0,0 +1,95 @@ +""" +FHRPGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting FHRPGroup entities: +- fhrp_group_minimal: Required fields only +- fhrp_group_extended: Common optional fields +- fhrp_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + FHRPGroup, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "fhrp_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a FHRPGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + fhrp_group = fhrp_group_minimal() + # fhrp_group = fhrp_group_extended() + # fhrp_group = fhrp_group_explicit() + + response = client.ingest(entities=[Entity(fhrp_group=fhrp_group)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("FHRPGroup ingested successfully") + + +def fhrp_group_minimal() -> FHRPGroup: + """Create a FHRPGroup with only required fields using flat strings.""" + return FHRPGroup( + protocol="carp", + group_id=1, + metadata={"source": "example"}, + ) + + +def fhrp_group_extended() -> FHRPGroup: + """Create a FHRPGroup with common optional fields.""" + return FHRPGroup( + protocol="carp", + group_id=1, + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + name="Example Name", + auth_type="md5", + auth_key="Example Auth Key", + comments="Example comments", + ) + + +def fhrp_group_explicit() -> FHRPGroup: + """Create a FHRPGroup with fully nested objects and all common fields.""" + return FHRPGroup( + protocol="carp", + group_id=1, + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + name="Example Name", + auth_type="md5", + auth_key="Example Auth Key", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/fhrp_group_assignment.py b/docs/examples/fhrp_group_assignment.py new file mode 100644 index 0000000..4c60662 --- /dev/null +++ b/docs/examples/fhrp_group_assignment.py @@ -0,0 +1,81 @@ +""" +FHRPGroupAssignment entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting FHRPGroupAssignment entities: +- fhrp_group_assignment_minimal: Required fields only +- fhrp_group_assignment_extended: Common optional fields +- fhrp_group_assignment_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + FHRPGroup, + FHRPGroupAssignment, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "fhrp_group_assignment-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a FHRPGroupAssignment entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + fhrp_group_assignment = fhrp_group_assignment_minimal() + # fhrp_group_assignment = fhrp_group_assignment_extended() + # fhrp_group_assignment = fhrp_group_assignment_explicit() + + response = client.ingest( + entities=[Entity(fhrp_group_assignment=fhrp_group_assignment)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("FHRPGroupAssignment ingested successfully") + + +def fhrp_group_assignment_minimal() -> FHRPGroupAssignment: + """Create a FHRPGroupAssignment with only required fields using flat strings.""" + return FHRPGroupAssignment( + group="Example Group", # flat string -> FHRPGroup + priority=1, + metadata={"source": "example"}, + ) + + +def fhrp_group_assignment_extended() -> FHRPGroupAssignment: + """Create a FHRPGroupAssignment with common optional fields.""" + return FHRPGroupAssignment( + group="Example Group", + priority=1, + metadata={"source": "example", "custom_key": "custom_value"}, + ) + + +def fhrp_group_assignment_explicit() -> FHRPGroupAssignment: + """Create a FHRPGroupAssignment with fully nested objects and all common fields.""" + return FHRPGroupAssignment( + group=FHRPGroup( + protocol="Example Protocol", group_id=1, metadata={"source": "example"} + ), + priority=1, + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/front_port.py b/docs/examples/front_port.py new file mode 100644 index 0000000..37fe25d --- /dev/null +++ b/docs/examples/front_port.py @@ -0,0 +1,237 @@ +""" +FrontPort entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting FrontPort entities: +- front_port_minimal: Required fields only +- front_port_extended: Common optional fields +- front_port_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + FrontPort, + Manufacturer, + Module, + ModuleBay, + ModuleType, + Owner, + OwnerGroup, + RearPort, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "front_port-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a FrontPort entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + front_port = front_port_minimal() + # front_port = front_port_extended() + # front_port = front_port_explicit() + + response = client.ingest(entities=[Entity(front_port=front_port)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("FrontPort ingested successfully") + + +def front_port_minimal() -> FrontPort: + """Create a FrontPort with only required fields using flat strings.""" + return FrontPort( + device="Example Device", # flat string -> Device + name="Example Name", + type="110-punch", + rear_port="Example Rear Port", # flat string -> RearPort + metadata={"source": "example"}, + ) + + +def front_port_extended() -> FrontPort: + """Create a FrontPort with common optional fields.""" + return FrontPort( + device="Example Device", + name="Example Name", + type="110-punch", + rear_port="Example Rear Port", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + color="0000ff", + label="Example Label", + rear_port_position=1, + mark_connected=True, + positions=1, + ) + + +def front_port_explicit() -> FrontPort: + """Create a FrontPort with fully nested objects and all common fields.""" + return FrontPort( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="110-punch", + rear_port=RearPort( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="Example Type", + color="0000ff", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + color="0000ff", + label="Example Label", + rear_port_position=1, + mark_connected=True, + positions=1, + module=Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/ike_policy.py b/docs/examples/ike_policy.py new file mode 100644 index 0000000..1302a90 --- /dev/null +++ b/docs/examples/ike_policy.py @@ -0,0 +1,93 @@ +""" +IKEPolicy entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting IKEPolicy entities: +- ike_policy_minimal: Required fields only +- ike_policy_extended: Common optional fields +- ike_policy_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + IKEPolicy, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "ike_policy-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a IKEPolicy entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + ike_policy = ike_policy_minimal() + # ike_policy = ike_policy_extended() + # ike_policy = ike_policy_explicit() + + response = client.ingest(entities=[Entity(ike_policy=ike_policy)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("IKEPolicy ingested successfully") + + +def ike_policy_minimal() -> IKEPolicy: + """Create a IKEPolicy with only required fields using flat strings.""" + return IKEPolicy( + name="Example Name", + version=1, + metadata={"source": "example"}, + ) + + +def ike_policy_extended() -> IKEPolicy: + """Create a IKEPolicy with common optional fields.""" + return IKEPolicy( + name="Example Name", + version=1, + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + mode="aggressive", + preshared_key="Example Preshared Key", + comments="Example comments", + ) + + +def ike_policy_explicit() -> IKEPolicy: + """Create a IKEPolicy with fully nested objects and all common fields.""" + return IKEPolicy( + name="Example Name", + version=1, + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + mode="aggressive", + preshared_key="Example Preshared Key", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/ike_proposal.py b/docs/examples/ike_proposal.py new file mode 100644 index 0000000..5b22b52 --- /dev/null +++ b/docs/examples/ike_proposal.py @@ -0,0 +1,99 @@ +""" +IKEProposal entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting IKEProposal entities: +- ike_proposal_minimal: Required fields only +- ike_proposal_extended: Common optional fields +- ike_proposal_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + IKEProposal, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "ike_proposal-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a IKEProposal entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + ike_proposal = ike_proposal_minimal() + # ike_proposal = ike_proposal_extended() + # ike_proposal = ike_proposal_explicit() + + response = client.ingest(entities=[Entity(ike_proposal=ike_proposal)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("IKEProposal ingested successfully") + + +def ike_proposal_minimal() -> IKEProposal: + """Create a IKEProposal with only required fields using flat strings.""" + return IKEProposal( + name="Example Name", + authentication_method="certificates", + encryption_algorithm="3des-cbc", + group=1, + metadata={"source": "example"}, + ) + + +def ike_proposal_extended() -> IKEProposal: + """Create a IKEProposal with common optional fields.""" + return IKEProposal( + name="Example Name", + authentication_method="certificates", + encryption_algorithm="3des-cbc", + group=1, + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + authentication_algorithm="hmac-md5", + sa_lifetime=1, + comments="Example comments", + ) + + +def ike_proposal_explicit() -> IKEProposal: + """Create a IKEProposal with fully nested objects and all common fields.""" + return IKEProposal( + name="Example Name", + authentication_method="certificates", + encryption_algorithm="3des-cbc", + group=1, + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + authentication_algorithm="hmac-md5", + sa_lifetime=1, + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/interface_example.py b/docs/examples/interface_example.py new file mode 100644 index 0000000..98e9f06 --- /dev/null +++ b/docs/examples/interface_example.py @@ -0,0 +1,334 @@ +""" +Interface entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Interface entities: +- interface_example_minimal: Required fields only +- interface_example_extended: Common optional fields +- interface_example_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Interface, + MACAddress, + Manufacturer, + Module, + ModuleBay, + ModuleType, + Owner, + OwnerGroup, + Site, + Tag, + VLAN, + VLANTranslationPolicy, + VRF, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "interface-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Interface entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + interface = interface_example_minimal() + # interface = interface_example_extended() + # interface = interface_example_explicit() + + response = client.ingest(entities=[Entity(interface=interface)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Interface ingested successfully") + + +def interface_example_minimal() -> Interface: + """Create a Interface with only required fields using flat strings.""" + return Interface( + device="Example Device", # flat string -> Device + name="Example Name", + type="1000base-bx10-d", + metadata={"source": "example"}, + ) + + +def interface_example_extended() -> Interface: + """Create a Interface with common optional fields.""" + return Interface( + device="Example Device", + name="Example Name", + type="1000base-bx10-d", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + label="Example Label", + enabled=True, + mtu=1, + speed=1, + duplex="auto", + wwn="Example Wwn", + mgmt_only=True, + mode="access", + rf_role="ap", + rf_channel="2.4g-1-2412-22", + poe_mode="pd", + poe_type="passive-24v-2pair", + rf_channel_frequency=1.0, + rf_channel_width=1.0, + tx_power=1, + mark_connected=True, + ) + + +def interface_example_explicit() -> Interface: + """Create a Interface with fully nested objects and all common fields.""" + return Interface( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="1000base-bx10-d", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + label="Example Label", + enabled=True, + mtu=1, + speed=1, + duplex="auto", + wwn="Example Wwn", + mgmt_only=True, + mode="access", + rf_role="ap", + rf_channel="2.4g-1-2412-22", + poe_mode="pd", + poe_type="passive-24v-2pair", + rf_channel_frequency=1.0, + rf_channel_width=1.0, + tx_power=1, + mark_connected=True, + module=Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + parent=Interface( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="Example Type", + metadata={"source": "example"}, + ), + bridge=Interface( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="Example Type", + metadata={"source": "example"}, + ), + lag=Interface( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="Example Type", + metadata={"source": "example"}, + ), + primary_mac_address=MACAddress( + mac_address="00:11:22:33:44:55", metadata={"source": "example"} + ), + untagged_vlan=VLAN( + vid=1, name="Example Name", status="active", metadata={"source": "example"} + ), + qinq_svlan=VLAN( + vid=1, name="Example Name", status="active", metadata={"source": "example"} + ), + vlan_translation_policy=VLANTranslationPolicy( + name="Example Name", metadata={"source": "example"} + ), + vrf=VRF(name="Example Name", metadata={"source": "example"}), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/inventory_item.py b/docs/examples/inventory_item.py new file mode 100644 index 0000000..56ce544 --- /dev/null +++ b/docs/examples/inventory_item.py @@ -0,0 +1,172 @@ +""" +InventoryItem entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting InventoryItem entities: +- inventory_item_minimal: Required fields only +- inventory_item_extended: Common optional fields +- inventory_item_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + InventoryItem, + InventoryItemRole, + Manufacturer, + Owner, + OwnerGroup, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "inventory_item-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a InventoryItem entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + inventory_item = inventory_item_minimal() + # inventory_item = inventory_item_extended() + # inventory_item = inventory_item_explicit() + + response = client.ingest(entities=[Entity(inventory_item=inventory_item)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("InventoryItem ingested successfully") + + +def inventory_item_minimal() -> InventoryItem: + """Create a InventoryItem with only required fields using flat strings.""" + return InventoryItem( + device="Example Device", # flat string -> Device + name="Example Name", + metadata={"source": "example"}, + ) + + +def inventory_item_extended() -> InventoryItem: + """Create a InventoryItem with common optional fields.""" + return InventoryItem( + device="Example Device", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + serial="SN-001234", + description="Example description", + label="Example Label", + role="Example Role", + manufacturer="Example Manufacturer", + part_id="Example Part Id", + asset_tag="ASSET-001", + discovered=True, + ) + + +def inventory_item_explicit() -> InventoryItem: + """Create a InventoryItem with fully nested objects and all common fields.""" + return InventoryItem( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + serial="SN-001234", + description="Example description", + asset_tag="ASSET-001", + label="Example Label", + part_id="Example Part Id", + discovered=True, + parent=InventoryItem( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + status="active", + metadata={"source": "example"}, + ), + role=InventoryItemRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + manufacturer=Manufacturer( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/inventory_item_role.py b/docs/examples/inventory_item_role.py new file mode 100644 index 0000000..f62d423 --- /dev/null +++ b/docs/examples/inventory_item_role.py @@ -0,0 +1,93 @@ +""" +InventoryItemRole entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting InventoryItemRole entities: +- inventory_item_role_minimal: Required fields only +- inventory_item_role_extended: Common optional fields +- inventory_item_role_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + InventoryItemRole, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "inventory_item_role-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a InventoryItemRole entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + inventory_item_role = inventory_item_role_minimal() + # inventory_item_role = inventory_item_role_extended() + # inventory_item_role = inventory_item_role_explicit() + + response = client.ingest( + entities=[Entity(inventory_item_role=inventory_item_role)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("InventoryItemRole ingested successfully") + + +def inventory_item_role_minimal() -> InventoryItemRole: + """Create a InventoryItemRole with only required fields using flat strings.""" + return InventoryItemRole( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def inventory_item_role_extended() -> InventoryItemRole: + """Create a InventoryItemRole with common optional fields.""" + return InventoryItemRole( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + color="0000ff", + comments="Example comments", + ) + + +def inventory_item_role_explicit() -> InventoryItemRole: + """Create a InventoryItemRole with fully nested objects and all common fields.""" + return InventoryItemRole( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + color="0000ff", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/ip_address.py b/docs/examples/ip_address.py new file mode 100644 index 0000000..7b61aba --- /dev/null +++ b/docs/examples/ip_address.py @@ -0,0 +1,102 @@ +""" +IPAddress entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting IPAddress entities: +- ip_address_minimal: Required fields only +- ip_address_extended: Common optional fields +- ip_address_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + IPAddress, + Owner, + OwnerGroup, + Tag, + Tenant, + VRF, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "ip_address-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a IPAddress entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + ip_address = ip_address_minimal() + # ip_address = ip_address_extended() + # ip_address = ip_address_explicit() + + response = client.ingest(entities=[Entity(ip_address=ip_address)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("IPAddress ingested successfully") + + +def ip_address_minimal() -> IPAddress: + """Create a IPAddress with only required fields using flat strings.""" + return IPAddress( + address="192.0.2.1/32", + metadata={"source": "example"}, + ) + + +def ip_address_extended() -> IPAddress: + """Create a IPAddress with common optional fields.""" + return IPAddress( + address="192.0.2.1/32", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + tenant="Example Tenant", + role="anycast", + dns_name="Example Dns Name", + comments="Example comments", + ) + + +def ip_address_explicit() -> IPAddress: + """Create a IPAddress with fully nested objects and all common fields.""" + return IPAddress( + address="192.0.2.1/32", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + role="anycast", + dns_name="Example Dns Name", + vrf=VRF(name="Example Name", metadata={"source": "example"}), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + nat_inside=IPAddress( + address="192.0.2.1/32", status="active", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/ip_range.py b/docs/examples/ip_range.py new file mode 100644 index 0000000..616a0da --- /dev/null +++ b/docs/examples/ip_range.py @@ -0,0 +1,107 @@ +""" +IPRange entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting IPRange entities: +- ip_range_minimal: Required fields only +- ip_range_extended: Common optional fields +- ip_range_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + IPRange, + Owner, + OwnerGroup, + Role, + Tag, + Tenant, + VRF, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "ip_range-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a IPRange entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + ip_range = ip_range_minimal() + # ip_range = ip_range_extended() + # ip_range = ip_range_explicit() + + response = client.ingest(entities=[Entity(ip_range=ip_range)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("IPRange ingested successfully") + + +def ip_range_minimal() -> IPRange: + """Create a IPRange with only required fields using flat strings.""" + return IPRange( + start_address="Example Start Address", + end_address="Example End Address", + metadata={"source": "example"}, + ) + + +def ip_range_extended() -> IPRange: + """Create a IPRange with common optional fields.""" + return IPRange( + start_address="Example Start Address", + end_address="Example End Address", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + tenant="Example Tenant", + role="Example Role", + comments="Example comments", + mark_utilized=True, + mark_populated=True, + ) + + +def ip_range_explicit() -> IPRange: + """Create a IPRange with fully nested objects and all common fields.""" + return IPRange( + start_address="Example Start Address", + end_address="Example End Address", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + mark_utilized=True, + mark_populated=True, + vrf=VRF(name="Example Name", metadata={"source": "example"}), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + role=Role( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/ip_sec_policy.py b/docs/examples/ip_sec_policy.py new file mode 100644 index 0000000..efed61b --- /dev/null +++ b/docs/examples/ip_sec_policy.py @@ -0,0 +1,88 @@ +""" +IPSecPolicy entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting IPSecPolicy entities: +- ip_sec_policy_minimal: Required fields only +- ip_sec_policy_extended: Common optional fields +- ip_sec_policy_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + IPSecPolicy, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "ip_sec_policy-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a IPSecPolicy entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + ip_sec_policy = ip_sec_policy_minimal() + # ip_sec_policy = ip_sec_policy_extended() + # ip_sec_policy = ip_sec_policy_explicit() + + response = client.ingest(entities=[Entity(ip_sec_policy=ip_sec_policy)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("IPSecPolicy ingested successfully") + + +def ip_sec_policy_minimal() -> IPSecPolicy: + """Create a IPSecPolicy with only required fields using flat strings.""" + return IPSecPolicy( + name="Example Name", + metadata={"source": "example"}, + ) + + +def ip_sec_policy_extended() -> IPSecPolicy: + """Create a IPSecPolicy with common optional fields.""" + return IPSecPolicy( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + pfs_group=1, + comments="Example comments", + ) + + +def ip_sec_policy_explicit() -> IPSecPolicy: + """Create a IPSecPolicy with fully nested objects and all common fields.""" + return IPSecPolicy( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + pfs_group=1, + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/ip_sec_profile.py b/docs/examples/ip_sec_profile.py new file mode 100644 index 0000000..9a2230c --- /dev/null +++ b/docs/examples/ip_sec_profile.py @@ -0,0 +1,99 @@ +""" +IPSecProfile entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting IPSecProfile entities: +- ip_sec_profile_minimal: Required fields only +- ip_sec_profile_extended: Common optional fields +- ip_sec_profile_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + IKEPolicy, + IPSecPolicy, + IPSecProfile, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "ip_sec_profile-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a IPSecProfile entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + ip_sec_profile = ip_sec_profile_minimal() + # ip_sec_profile = ip_sec_profile_extended() + # ip_sec_profile = ip_sec_profile_explicit() + + response = client.ingest(entities=[Entity(ip_sec_profile=ip_sec_profile)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("IPSecProfile ingested successfully") + + +def ip_sec_profile_minimal() -> IPSecProfile: + """Create a IPSecProfile with only required fields using flat strings.""" + return IPSecProfile( + name="Example Name", + mode="ah", + ike_policy="Example Ike Policy", # flat string -> IKEPolicy + ipsec_policy="Example Ipsec Policy", # flat string -> IPSecPolicy + metadata={"source": "example"}, + ) + + +def ip_sec_profile_extended() -> IPSecProfile: + """Create a IPSecProfile with common optional fields.""" + return IPSecProfile( + name="Example Name", + mode="ah", + ike_policy="Example Ike Policy", + ipsec_policy="Example Ipsec Policy", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def ip_sec_profile_explicit() -> IPSecProfile: + """Create a IPSecProfile with fully nested objects and all common fields.""" + return IPSecProfile( + name="Example Name", + mode="ah", + ike_policy=IKEPolicy( + name="Example Name", version=1, metadata={"source": "example"} + ), + ipsec_policy=IPSecPolicy(name="Example Name", metadata={"source": "example"}), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/ip_sec_proposal.py b/docs/examples/ip_sec_proposal.py new file mode 100644 index 0000000..0e77389 --- /dev/null +++ b/docs/examples/ip_sec_proposal.py @@ -0,0 +1,94 @@ +""" +IPSecProposal entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting IPSecProposal entities: +- ip_sec_proposal_minimal: Required fields only +- ip_sec_proposal_extended: Common optional fields +- ip_sec_proposal_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + IPSecProposal, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "ip_sec_proposal-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a IPSecProposal entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + ip_sec_proposal = ip_sec_proposal_minimal() + # ip_sec_proposal = ip_sec_proposal_extended() + # ip_sec_proposal = ip_sec_proposal_explicit() + + response = client.ingest(entities=[Entity(ip_sec_proposal=ip_sec_proposal)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("IPSecProposal ingested successfully") + + +def ip_sec_proposal_minimal() -> IPSecProposal: + """Create a IPSecProposal with only required fields using flat strings.""" + return IPSecProposal( + name="Example Name", + metadata={"source": "example"}, + ) + + +def ip_sec_proposal_extended() -> IPSecProposal: + """Create a IPSecProposal with common optional fields.""" + return IPSecProposal( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + encryption_algorithm="3des-cbc", + authentication_algorithm="hmac-md5", + sa_lifetime_seconds=1, + sa_lifetime_data=1, + comments="Example comments", + ) + + +def ip_sec_proposal_explicit() -> IPSecProposal: + """Create a IPSecProposal with fully nested objects and all common fields.""" + return IPSecProposal( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + encryption_algorithm="3des-cbc", + authentication_algorithm="hmac-md5", + sa_lifetime_seconds=1, + sa_lifetime_data=1, + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/journal_entry.py b/docs/examples/journal_entry.py new file mode 100644 index 0000000..31c7519 --- /dev/null +++ b/docs/examples/journal_entry.py @@ -0,0 +1,77 @@ +""" +JournalEntry entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting JournalEntry entities: +- journal_entry_minimal: Required fields only +- journal_entry_extended: Common optional fields +- journal_entry_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + JournalEntry, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "journal_entry-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a JournalEntry entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + journal_entry = journal_entry_minimal() + # journal_entry = journal_entry_extended() + # journal_entry = journal_entry_explicit() + + response = client.ingest(entities=[Entity(journal_entry=journal_entry)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("JournalEntry ingested successfully") + + +def journal_entry_minimal() -> JournalEntry: + """Create a JournalEntry with only required fields using flat strings.""" + return JournalEntry( + comments="Example comments", + metadata={"source": "example"}, + ) + + +def journal_entry_extended() -> JournalEntry: + """Create a JournalEntry with common optional fields.""" + return JournalEntry( + comments="Example comments", + metadata={"source": "example", "custom_key": "custom_value"}, + kind="danger", + ) + + +def journal_entry_explicit() -> JournalEntry: + """Create a JournalEntry with fully nested objects and all common fields.""" + return JournalEntry( + comments="Example comments", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + kind="danger", + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/l2vpn.py b/docs/examples/l2vpn.py new file mode 100644 index 0000000..e415971 --- /dev/null +++ b/docs/examples/l2vpn.py @@ -0,0 +1,100 @@ +""" +L2VPN entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting L2VPN entities: +- l2vpn_minimal: Required fields only +- l2vpn_extended: Common optional fields +- l2vpn_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + L2VPN, + Owner, + OwnerGroup, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "l2vpn-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a L2VPN entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + l2vpn = l2vpn_minimal() + # l2vpn = l2vpn_extended() + # l2vpn = l2vpn_explicit() + + response = client.ingest(entities=[Entity(l2vpn=l2vpn)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("L2VPN ingested successfully") + + +def l2vpn_minimal() -> L2VPN: + """Create a L2VPN with only required fields using flat strings.""" + return L2VPN( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def l2vpn_extended() -> L2VPN: + """Create a L2VPN with common optional fields.""" + return L2VPN( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + identifier=1, + type="ep-lan", + comments="Example comments", + tenant="Example Tenant", + ) + + +def l2vpn_explicit() -> L2VPN: + """Create a L2VPN with fully nested objects and all common fields.""" + return L2VPN( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + identifier=1, + type="ep-lan", + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/l2vpn_termination.py b/docs/examples/l2vpn_termination.py new file mode 100644 index 0000000..9f6d5dd --- /dev/null +++ b/docs/examples/l2vpn_termination.py @@ -0,0 +1,81 @@ +""" +L2VPNTermination entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting L2VPNTermination entities: +- l2vpn_termination_minimal: Required fields only +- l2vpn_termination_extended: Common optional fields +- l2vpn_termination_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + L2VPN, + L2VPNTermination, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "l2vpn_termination-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a L2VPNTermination entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + l2vpn_termination = l2vpn_termination_minimal() + # l2vpn_termination = l2vpn_termination_extended() + # l2vpn_termination = l2vpn_termination_explicit() + + response = client.ingest(entities=[Entity(l2vpn_termination=l2vpn_termination)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("L2VPNTermination ingested successfully") + + +def l2vpn_termination_minimal() -> L2VPNTermination: + """Create a L2VPNTermination with only required fields using flat strings.""" + return L2VPNTermination( + l2vpn="Example L2Vpn", # flat string -> L2VPN + metadata={"source": "example"}, + ) + + +def l2vpn_termination_extended() -> L2VPNTermination: + """Create a L2VPNTermination with common optional fields.""" + return L2VPNTermination( + l2vpn="Example L2Vpn", + metadata={"source": "example", "custom_key": "custom_value"}, + ) + + +def l2vpn_termination_explicit() -> L2VPNTermination: + """Create a L2VPNTermination with fully nested objects and all common fields.""" + return L2VPNTermination( + l2vpn=L2VPN( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/location.py b/docs/examples/location.py new file mode 100644 index 0000000..fce2585 --- /dev/null +++ b/docs/examples/location.py @@ -0,0 +1,119 @@ +""" +Location entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Location entities: +- location_minimal: Required fields only +- location_extended: Common optional fields +- location_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Location, + Owner, + OwnerGroup, + Site, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "location-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Location entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + location = location_minimal() + # location = location_extended() + # location = location_explicit() + + response = client.ingest(entities=[Entity(location=location)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Location ingested successfully") + + +def location_minimal() -> Location: + """Create a Location with only required fields using flat strings.""" + return Location( + name="Example Name", + slug="example-slug", + site="Example Site", # flat string -> Site + metadata={"source": "example"}, + ) + + +def location_extended() -> Location: + """Create a Location with common optional fields.""" + return Location( + name="Example Name", + slug="example-slug", + site="Example Site", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + tenant="Example Tenant", + facility="Example Facility", + comments="Example comments", + ) + + +def location_explicit() -> Location: + """Create a Location with fully nested objects and all common fields.""" + return Location( + name="Example Name", + slug="example-slug", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + facility="Example Facility", + parent=Location( + name="Example Name", + slug="example-slug", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/mac_address.py b/docs/examples/mac_address.py new file mode 100644 index 0000000..ea08a07 --- /dev/null +++ b/docs/examples/mac_address.py @@ -0,0 +1,86 @@ +""" +MACAddress entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting MACAddress entities: +- mac_address_minimal: Required fields only +- mac_address_extended: Common optional fields +- mac_address_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + MACAddress, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "mac_address-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a MACAddress entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + mac_address = mac_address_minimal() + # mac_address = mac_address_extended() + # mac_address = mac_address_explicit() + + response = client.ingest(entities=[Entity(mac_address=mac_address)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("MACAddress ingested successfully") + + +def mac_address_minimal() -> MACAddress: + """Create a MACAddress with only required fields using flat strings.""" + return MACAddress( + mac_address="00:11:22:33:44:55", + metadata={"source": "example"}, + ) + + +def mac_address_extended() -> MACAddress: + """Create a MACAddress with common optional fields.""" + return MACAddress( + mac_address="00:11:22:33:44:55", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def mac_address_explicit() -> MACAddress: + """Create a MACAddress with fully nested objects and all common fields.""" + return MACAddress( + mac_address="00:11:22:33:44:55", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/manufacturer.py b/docs/examples/manufacturer.py new file mode 100644 index 0000000..084f34c --- /dev/null +++ b/docs/examples/manufacturer.py @@ -0,0 +1,89 @@ +""" +Manufacturer entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Manufacturer entities: +- manufacturer_minimal: Required fields only +- manufacturer_extended: Common optional fields +- manufacturer_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Manufacturer, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "manufacturer-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Manufacturer entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + manufacturer = manufacturer_minimal() + # manufacturer = manufacturer_extended() + # manufacturer = manufacturer_explicit() + + response = client.ingest(entities=[Entity(manufacturer=manufacturer)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Manufacturer ingested successfully") + + +def manufacturer_minimal() -> Manufacturer: + """Create a Manufacturer with only required fields using flat strings.""" + return Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def manufacturer_extended() -> Manufacturer: + """Create a Manufacturer with common optional fields.""" + return Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def manufacturer_explicit() -> Manufacturer: + """Create a Manufacturer with fully nested objects and all common fields.""" + return Manufacturer( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/module.py b/docs/examples/module.py new file mode 100644 index 0000000..991b13e --- /dev/null +++ b/docs/examples/module.py @@ -0,0 +1,165 @@ +""" +Module entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Module entities: +- module_minimal: Required fields only +- module_extended: Common optional fields +- module_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Module, + ModuleBay, + ModuleType, + Owner, + OwnerGroup, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "module-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Module entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + module = module_minimal() + # module = module_extended() + # module = module_explicit() + + response = client.ingest(entities=[Entity(module=module)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Module ingested successfully") + + +def module_minimal() -> Module: + """Create a Module with only required fields using flat strings.""" + return Module( + device="Example Device", # flat string -> Device + module_bay="Example Module Bay", # flat string -> ModuleBay + module_type="Example Module Type", # flat string -> ModuleType + metadata={"source": "example"}, + ) + + +def module_extended() -> Module: + """Create a Module with common optional fields.""" + return Module( + device="Example Device", + module_bay="Example Module Bay", + module_type="Example Module Type", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + serial="SN-001234", + description="Example description", + asset_tag="ASSET-001", + comments="Example comments", + ) + + +def module_explicit() -> Module: + """Create a Module with fully nested objects and all common fields.""" + return Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + model="Model X", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + serial="SN-001234", + description="Example description", + comments="Example comments", + asset_tag="ASSET-001", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/module_bay.py b/docs/examples/module_bay.py new file mode 100644 index 0000000..a16b3de --- /dev/null +++ b/docs/examples/module_bay.py @@ -0,0 +1,261 @@ +""" +ModuleBay entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ModuleBay entities: +- module_bay_minimal: Required fields only +- module_bay_extended: Common optional fields +- module_bay_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Module, + ModuleBay, + ModuleType, + Owner, + OwnerGroup, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "module_bay-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ModuleBay entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + module_bay = module_bay_minimal() + # module_bay = module_bay_extended() + # module_bay = module_bay_explicit() + + response = client.ingest(entities=[Entity(module_bay=module_bay)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ModuleBay ingested successfully") + + +def module_bay_minimal() -> ModuleBay: + """Create a ModuleBay with only required fields using flat strings.""" + return ModuleBay( + device="Example Device", # flat string -> Device + name="Example Name", + metadata={"source": "example"}, + ) + + +def module_bay_extended() -> ModuleBay: + """Create a ModuleBay with common optional fields.""" + return ModuleBay( + device="Example Device", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + label="Example Label", + position="Example Position", + ) + + +def module_bay_explicit() -> ModuleBay: + """Create a ModuleBay with fully nested objects and all common fields.""" + return ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + label="Example Label", + position="Example Position", + module=Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + installed_module=Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/module_type.py b/docs/examples/module_type.py new file mode 100644 index 0000000..285b312 --- /dev/null +++ b/docs/examples/module_type.py @@ -0,0 +1,104 @@ +""" +ModuleType entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ModuleType entities: +- module_type_minimal: Required fields only +- module_type_extended: Common optional fields +- module_type_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Manufacturer, + ModuleType, + ModuleTypeProfile, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "module_type-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ModuleType entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + module_type = module_type_minimal() + # module_type = module_type_extended() + # module_type = module_type_explicit() + + response = client.ingest(entities=[Entity(module_type=module_type)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ModuleType ingested successfully") + + +def module_type_minimal() -> ModuleType: + """Create a ModuleType with only required fields using flat strings.""" + return ModuleType( + manufacturer="Example Manufacturer", # flat string -> Manufacturer + model="Model X", + metadata={"source": "example"}, + ) + + +def module_type_extended() -> ModuleType: + """Create a ModuleType with common optional fields.""" + return ModuleType( + manufacturer="Example Manufacturer", + model="Model X", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + part_number="Example Part Number", + airflow="front-to-rear", + weight=1.0, + weight_unit="g", + comments="Example comments", + attributes="Example Attributes", + ) + + +def module_type_explicit() -> ModuleType: + """Create a ModuleType with fully nested objects and all common fields.""" + return ModuleType( + manufacturer=Manufacturer( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + model="Model X", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + part_number="Example Part Number", + airflow="front-to-rear", + weight=1.0, + weight_unit="g", + attributes="Example Attributes", + profile=ModuleTypeProfile(name="Example Name", metadata={"source": "example"}), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/module_type_profile.py b/docs/examples/module_type_profile.py new file mode 100644 index 0000000..1569bd2 --- /dev/null +++ b/docs/examples/module_type_profile.py @@ -0,0 +1,90 @@ +""" +ModuleTypeProfile entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ModuleTypeProfile entities: +- module_type_profile_minimal: Required fields only +- module_type_profile_extended: Common optional fields +- module_type_profile_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + ModuleTypeProfile, + Owner, + OwnerGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "module_type_profile-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ModuleTypeProfile entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + module_type_profile = module_type_profile_minimal() + # module_type_profile = module_type_profile_extended() + # module_type_profile = module_type_profile_explicit() + + response = client.ingest( + entities=[Entity(module_type_profile=module_type_profile)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ModuleTypeProfile ingested successfully") + + +def module_type_profile_minimal() -> ModuleTypeProfile: + """Create a ModuleTypeProfile with only required fields using flat strings.""" + return ModuleTypeProfile( + name="Example Name", + metadata={"source": "example"}, + ) + + +def module_type_profile_extended() -> ModuleTypeProfile: + """Create a ModuleTypeProfile with common optional fields.""" + return ModuleTypeProfile( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + schema="Example Schema", + comments="Example comments", + ) + + +def module_type_profile_explicit() -> ModuleTypeProfile: + """Create a ModuleTypeProfile with fully nested objects and all common fields.""" + return ModuleTypeProfile( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + schema="Example Schema", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/owner.py b/docs/examples/owner.py new file mode 100644 index 0000000..ab8fadc --- /dev/null +++ b/docs/examples/owner.py @@ -0,0 +1,79 @@ +""" +Owner entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Owner entities: +- owner_minimal: Required fields only +- owner_extended: Common optional fields +- owner_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "owner-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Owner entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + owner = owner_minimal() + # owner = owner_extended() + # owner = owner_explicit() + + response = client.ingest(entities=[Entity(owner=owner)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Owner ingested successfully") + + +def owner_minimal() -> Owner: + """Create a Owner with only required fields using flat strings.""" + return Owner( + name="Example Name", + group="Example Group", # flat string -> OwnerGroup + metadata={"source": "example"}, + ) + + +def owner_extended() -> Owner: + """Create a Owner with common optional fields.""" + return Owner( + name="Example Name", + group="Example Group", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + ) + + +def owner_explicit() -> Owner: + """Create a Owner with fully nested objects and all common fields.""" + return Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/owner_group.py b/docs/examples/owner_group.py new file mode 100644 index 0000000..35b5832 --- /dev/null +++ b/docs/examples/owner_group.py @@ -0,0 +1,71 @@ +""" +OwnerGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting OwnerGroup entities: +- owner_group_minimal: Required fields only +- owner_group_extended: Common optional fields +- owner_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "owner_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a OwnerGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + owner_group = owner_group_minimal() + # owner_group = owner_group_extended() + # owner_group = owner_group_explicit() + + response = client.ingest(entities=[Entity(owner_group=owner_group)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("OwnerGroup ingested successfully") + + +def owner_group_minimal() -> OwnerGroup: + """Create a OwnerGroup with only required fields using flat strings.""" + return OwnerGroup( + name="Example Name", + metadata={"source": "example"}, + ) + + +def owner_group_extended() -> OwnerGroup: + """Create a OwnerGroup with common optional fields.""" + return OwnerGroup( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + ) + + +def owner_group_explicit() -> OwnerGroup: + """Create a OwnerGroup with fully nested objects and all common fields.""" + return OwnerGroup( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/platform.py b/docs/examples/platform.py new file mode 100644 index 0000000..f3975ab --- /dev/null +++ b/docs/examples/platform.py @@ -0,0 +1,97 @@ +""" +Platform entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Platform entities: +- platform_minimal: Required fields only +- platform_extended: Common optional fields +- platform_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Manufacturer, + Owner, + OwnerGroup, + Platform, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "platform-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Platform entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + platform = platform_minimal() + # platform = platform_extended() + # platform = platform_explicit() + + response = client.ingest(entities=[Entity(platform=platform)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Platform ingested successfully") + + +def platform_minimal() -> Platform: + """Create a Platform with only required fields using flat strings.""" + return Platform( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def platform_extended() -> Platform: + """Create a Platform with common optional fields.""" + return Platform( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + manufacturer="Example Manufacturer", + comments="Example comments", + ) + + +def platform_explicit() -> Platform: + """Create a Platform with fully nested objects and all common fields.""" + return Platform( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + manufacturer=Manufacturer( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + parent=Platform( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/power_feed.py b/docs/examples/power_feed.py new file mode 100644 index 0000000..23f2b0e --- /dev/null +++ b/docs/examples/power_feed.py @@ -0,0 +1,134 @@ +""" +PowerFeed entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting PowerFeed entities: +- power_feed_minimal: Required fields only +- power_feed_extended: Common optional fields +- power_feed_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + PowerFeed, + PowerPanel, + Rack, + Site, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "power_feed-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a PowerFeed entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + power_feed = power_feed_minimal() + # power_feed = power_feed_extended() + # power_feed = power_feed_explicit() + + response = client.ingest(entities=[Entity(power_feed=power_feed)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("PowerFeed ingested successfully") + + +def power_feed_minimal() -> PowerFeed: + """Create a PowerFeed with only required fields using flat strings.""" + return PowerFeed( + power_panel="Example Power Panel", # flat string -> PowerPanel + name="Example Name", + metadata={"source": "example"}, + ) + + +def power_feed_extended() -> PowerFeed: + """Create a PowerFeed with common optional fields.""" + return PowerFeed( + power_panel="Example Power Panel", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + rack="Example Rack", + type="primary", + supply="ac", + phase="single-phase", + voltage=1, + amperage=1, + max_utilization=1, + mark_connected=True, + tenant="Example Tenant", + comments="Example comments", + ) + + +def power_feed_explicit() -> PowerFeed: + """Create a PowerFeed with fully nested objects and all common fields.""" + return PowerFeed( + power_panel=PowerPanel( + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + type="primary", + supply="ac", + phase="single-phase", + voltage=1, + amperage=1, + max_utilization=1, + mark_connected=True, + rack=Rack( + name="Example Name", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/power_outlet.py b/docs/examples/power_outlet.py new file mode 100644 index 0000000..a5aad5c --- /dev/null +++ b/docs/examples/power_outlet.py @@ -0,0 +1,232 @@ +""" +PowerOutlet entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting PowerOutlet entities: +- power_outlet_minimal: Required fields only +- power_outlet_extended: Common optional fields +- power_outlet_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Module, + ModuleBay, + ModuleType, + Owner, + OwnerGroup, + PowerOutlet, + PowerPort, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "power_outlet-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a PowerOutlet entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + power_outlet = power_outlet_minimal() + # power_outlet = power_outlet_extended() + # power_outlet = power_outlet_explicit() + + response = client.ingest(entities=[Entity(power_outlet=power_outlet)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("PowerOutlet ingested successfully") + + +def power_outlet_minimal() -> PowerOutlet: + """Create a PowerOutlet with only required fields using flat strings.""" + return PowerOutlet( + device="Example Device", # flat string -> Device + name="Example Name", + metadata={"source": "example"}, + ) + + +def power_outlet_extended() -> PowerOutlet: + """Create a PowerOutlet with common optional fields.""" + return PowerOutlet( + device="Example Device", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + status="disabled", + description="Example description", + color="0000ff", + label="Example Label", + type="CS6360C", + feed_leg="A", + mark_connected=True, + ) + + +def power_outlet_explicit() -> PowerOutlet: + """Create a PowerOutlet with fully nested objects and all common fields.""" + return PowerOutlet( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="disabled", + description="Example description", + color="0000ff", + label="Example Label", + type="CS6360C", + feed_leg="A", + mark_connected=True, + module=Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + power_port=PowerPort( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/power_panel.py b/docs/examples/power_panel.py new file mode 100644 index 0000000..25316e0 --- /dev/null +++ b/docs/examples/power_panel.py @@ -0,0 +1,109 @@ +""" +PowerPanel entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting PowerPanel entities: +- power_panel_minimal: Required fields only +- power_panel_extended: Common optional fields +- power_panel_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Location, + Owner, + OwnerGroup, + PowerPanel, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "power_panel-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a PowerPanel entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + power_panel = power_panel_minimal() + # power_panel = power_panel_extended() + # power_panel = power_panel_explicit() + + response = client.ingest(entities=[Entity(power_panel=power_panel)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("PowerPanel ingested successfully") + + +def power_panel_minimal() -> PowerPanel: + """Create a PowerPanel with only required fields using flat strings.""" + return PowerPanel( + site="Example Site", # flat string -> Site + name="Example Name", + metadata={"source": "example"}, + ) + + +def power_panel_extended() -> PowerPanel: + """Create a PowerPanel with common optional fields.""" + return PowerPanel( + site="Example Site", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + location="Example Location", + comments="Example comments", + ) + + +def power_panel_explicit() -> PowerPanel: + """Create a PowerPanel with fully nested objects and all common fields.""" + return PowerPanel( + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + location=Location( + name="Example Name", + slug="example-slug", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/power_port.py b/docs/examples/power_port.py new file mode 100644 index 0000000..b19bee3 --- /dev/null +++ b/docs/examples/power_port.py @@ -0,0 +1,199 @@ +""" +PowerPort entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting PowerPort entities: +- power_port_minimal: Required fields only +- power_port_extended: Common optional fields +- power_port_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Module, + ModuleBay, + ModuleType, + Owner, + OwnerGroup, + PowerPort, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "power_port-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a PowerPort entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + power_port = power_port_minimal() + # power_port = power_port_extended() + # power_port = power_port_explicit() + + response = client.ingest(entities=[Entity(power_port=power_port)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("PowerPort ingested successfully") + + +def power_port_minimal() -> PowerPort: + """Create a PowerPort with only required fields using flat strings.""" + return PowerPort( + device="Example Device", # flat string -> Device + name="Example Name", + metadata={"source": "example"}, + ) + + +def power_port_extended() -> PowerPort: + """Create a PowerPort with common optional fields.""" + return PowerPort( + device="Example Device", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + label="Example Label", + type="cs6361c", + maximum_draw=1, + allocated_draw=1, + mark_connected=True, + ) + + +def power_port_explicit() -> PowerPort: + """Create a PowerPort with fully nested objects and all common fields.""" + return PowerPort( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + label="Example Label", + type="cs6361c", + maximum_draw=1, + allocated_draw=1, + mark_connected=True, + module=Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/prefix.py b/docs/examples/prefix.py new file mode 100644 index 0000000..0898a58 --- /dev/null +++ b/docs/examples/prefix.py @@ -0,0 +1,108 @@ +""" +Prefix entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Prefix entities: +- prefix_minimal: Required fields only +- prefix_extended: Common optional fields +- prefix_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Prefix, + Role, + Tag, + Tenant, + VLAN, + VRF, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "prefix-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Prefix entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + prefix = prefix_minimal() + # prefix = prefix_extended() + # prefix = prefix_explicit() + + response = client.ingest(entities=[Entity(prefix=prefix)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Prefix ingested successfully") + + +def prefix_minimal() -> Prefix: + """Create a Prefix with only required fields using flat strings.""" + return Prefix( + prefix="192.0.2.0/24", + metadata={"source": "example"}, + ) + + +def prefix_extended() -> Prefix: + """Create a Prefix with common optional fields.""" + return Prefix( + prefix="192.0.2.0/24", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + tenant="Example Tenant", + role="Example Role", + is_pool=True, + mark_utilized=True, + comments="Example comments", + ) + + +def prefix_explicit() -> Prefix: + """Create a Prefix with fully nested objects and all common fields.""" + return Prefix( + prefix="192.0.2.0/24", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + is_pool=True, + mark_utilized=True, + vrf=VRF(name="Example Name", metadata={"source": "example"}), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + vlan=VLAN( + vid=1, name="Example Name", status="active", metadata={"source": "example"} + ), + role=Role( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/provider.py b/docs/examples/provider.py new file mode 100644 index 0000000..58e792a --- /dev/null +++ b/docs/examples/provider.py @@ -0,0 +1,89 @@ +""" +Provider entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Provider entities: +- provider_minimal: Required fields only +- provider_extended: Common optional fields +- provider_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Provider, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "provider-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Provider entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + provider = provider_minimal() + # provider = provider_extended() + # provider = provider_explicit() + + response = client.ingest(entities=[Entity(provider=provider)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Provider ingested successfully") + + +def provider_minimal() -> Provider: + """Create a Provider with only required fields using flat strings.""" + return Provider( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def provider_extended() -> Provider: + """Create a Provider with common optional fields.""" + return Provider( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def provider_explicit() -> Provider: + """Create a Provider with fully nested objects and all common fields.""" + return Provider( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/provider_account.py b/docs/examples/provider_account.py new file mode 100644 index 0000000..448ba0b --- /dev/null +++ b/docs/examples/provider_account.py @@ -0,0 +1,94 @@ +""" +ProviderAccount entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ProviderAccount entities: +- provider_account_minimal: Required fields only +- provider_account_extended: Common optional fields +- provider_account_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Provider, + ProviderAccount, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "provider_account-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ProviderAccount entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + provider_account = provider_account_minimal() + # provider_account = provider_account_extended() + # provider_account = provider_account_explicit() + + response = client.ingest(entities=[Entity(provider_account=provider_account)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ProviderAccount ingested successfully") + + +def provider_account_minimal() -> ProviderAccount: + """Create a ProviderAccount with only required fields using flat strings.""" + return ProviderAccount( + provider="Example Provider", # flat string -> Provider + account="Example Account", + metadata={"source": "example"}, + ) + + +def provider_account_extended() -> ProviderAccount: + """Create a ProviderAccount with common optional fields.""" + return ProviderAccount( + provider="Example Provider", + account="Example Account", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + name="Example Name", + comments="Example comments", + ) + + +def provider_account_explicit() -> ProviderAccount: + """Create a ProviderAccount with fully nested objects and all common fields.""" + return ProviderAccount( + provider=Provider( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + account="Example Account", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + name="Example Name", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/provider_network.py b/docs/examples/provider_network.py new file mode 100644 index 0000000..2473218 --- /dev/null +++ b/docs/examples/provider_network.py @@ -0,0 +1,94 @@ +""" +ProviderNetwork entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting ProviderNetwork entities: +- provider_network_minimal: Required fields only +- provider_network_extended: Common optional fields +- provider_network_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Provider, + ProviderNetwork, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "provider_network-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a ProviderNetwork entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + provider_network = provider_network_minimal() + # provider_network = provider_network_extended() + # provider_network = provider_network_explicit() + + response = client.ingest(entities=[Entity(provider_network=provider_network)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("ProviderNetwork ingested successfully") + + +def provider_network_minimal() -> ProviderNetwork: + """Create a ProviderNetwork with only required fields using flat strings.""" + return ProviderNetwork( + provider="Example Provider", # flat string -> Provider + name="Example Name", + metadata={"source": "example"}, + ) + + +def provider_network_extended() -> ProviderNetwork: + """Create a ProviderNetwork with common optional fields.""" + return ProviderNetwork( + provider="Example Provider", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + service_id="Example Service Id", + comments="Example comments", + ) + + +def provider_network_explicit() -> ProviderNetwork: + """Create a ProviderNetwork with fully nested objects and all common fields.""" + return ProviderNetwork( + provider=Provider( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + service_id="Example Service Id", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/rack.py b/docs/examples/rack.py new file mode 100644 index 0000000..3200be5 --- /dev/null +++ b/docs/examples/rack.py @@ -0,0 +1,168 @@ +""" +Rack entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Rack entities: +- rack_minimal: Required fields only +- rack_extended: Common optional fields +- rack_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Location, + Manufacturer, + Owner, + OwnerGroup, + Rack, + RackRole, + RackType, + Site, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "rack-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Rack entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + rack = rack_minimal() + # rack = rack_extended() + # rack = rack_explicit() + + response = client.ingest(entities=[Entity(rack=rack)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Rack ingested successfully") + + +def rack_minimal() -> Rack: + """Create a Rack with only required fields using flat strings.""" + return Rack( + name="Example Name", + site="Example Site", # flat string -> Site + metadata={"source": "example"}, + ) + + +def rack_extended() -> Rack: + """Create a Rack with common optional fields.""" + return Rack( + name="Example Name", + site="Example Site", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + serial="SN-001234", + description="Example description", + facility_id="Example Facility Id", + location="Example Location", + tenant="Example Tenant", + role="Example Role", + asset_tag="ASSET-001", + form_factor="2-post-frame", + width=1, + u_height=1, + starting_unit=1, + weight=1.0, + max_weight=1, + weight_unit="g", + desc_units=True, + outer_width=1, + outer_depth=1, + outer_unit="in", + mounting_depth=1, + airflow="front-to-rear", + comments="Example comments", + outer_height=1, + ) + + +def rack_explicit() -> Rack: + """Create a Rack with fully nested objects and all common fields.""" + return Rack( + name="Example Name", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + serial="SN-001234", + description="Example description", + comments="Example comments", + asset_tag="ASSET-001", + facility_id="Example Facility Id", + form_factor="2-post-frame", + width=1, + u_height=1, + starting_unit=1, + weight=1.0, + max_weight=1, + weight_unit="g", + desc_units=True, + outer_width=1, + outer_depth=1, + outer_unit="in", + mounting_depth=1, + airflow="front-to-rear", + outer_height=1, + location=Location( + name="Example Name", + slug="example-slug", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + role=RackRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + rack_type=RackType( + manufacturer=Manufacturer( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/rack_reservation.py b/docs/examples/rack_reservation.py new file mode 100644 index 0000000..5ecedc9 --- /dev/null +++ b/docs/examples/rack_reservation.py @@ -0,0 +1,106 @@ +""" +RackReservation entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting RackReservation entities: +- rack_reservation_minimal: Required fields only +- rack_reservation_extended: Common optional fields +- rack_reservation_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Rack, + RackReservation, + Site, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "rack_reservation-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a RackReservation entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + rack_reservation = rack_reservation_minimal() + # rack_reservation = rack_reservation_extended() + # rack_reservation = rack_reservation_explicit() + + response = client.ingest(entities=[Entity(rack_reservation=rack_reservation)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("RackReservation ingested successfully") + + +def rack_reservation_minimal() -> RackReservation: + """Create a RackReservation with only required fields using flat strings.""" + return RackReservation( + rack="Example Rack", # flat string -> Rack + description="Example description", + metadata={"source": "example"}, + ) + + +def rack_reservation_extended() -> RackReservation: + """Create a RackReservation with common optional fields.""" + return RackReservation( + rack="Example Rack", + description="Example description", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + tenant="Example Tenant", + comments="Example comments", + ) + + +def rack_reservation_explicit() -> RackReservation: + """Create a RackReservation with fully nested objects and all common fields.""" + return RackReservation( + rack=Rack( + name="Example Name", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + description="Example description", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + comments="Example comments", + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/rack_role.py b/docs/examples/rack_role.py new file mode 100644 index 0000000..c926d02 --- /dev/null +++ b/docs/examples/rack_role.py @@ -0,0 +1,91 @@ +""" +RackRole entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting RackRole entities: +- rack_role_minimal: Required fields only +- rack_role_extended: Common optional fields +- rack_role_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + RackRole, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "rack_role-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a RackRole entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + rack_role = rack_role_minimal() + # rack_role = rack_role_extended() + # rack_role = rack_role_explicit() + + response = client.ingest(entities=[Entity(rack_role=rack_role)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("RackRole ingested successfully") + + +def rack_role_minimal() -> RackRole: + """Create a RackRole with only required fields using flat strings.""" + return RackRole( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def rack_role_extended() -> RackRole: + """Create a RackRole with common optional fields.""" + return RackRole( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + color="0000ff", + comments="Example comments", + ) + + +def rack_role_explicit() -> RackRole: + """Create a RackRole with fully nested objects and all common fields.""" + return RackRole( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + color="0000ff", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/rack_type.py b/docs/examples/rack_type.py new file mode 100644 index 0000000..ee4f3f4 --- /dev/null +++ b/docs/examples/rack_type.py @@ -0,0 +1,121 @@ +""" +RackType entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting RackType entities: +- rack_type_minimal: Required fields only +- rack_type_extended: Common optional fields +- rack_type_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Manufacturer, + Owner, + OwnerGroup, + RackType, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "rack_type-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a RackType entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + rack_type = rack_type_minimal() + # rack_type = rack_type_extended() + # rack_type = rack_type_explicit() + + response = client.ingest(entities=[Entity(rack_type=rack_type)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("RackType ingested successfully") + + +def rack_type_minimal() -> RackType: + """Create a RackType with only required fields using flat strings.""" + return RackType( + manufacturer="Example Manufacturer", # flat string -> Manufacturer + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def rack_type_extended() -> RackType: + """Create a RackType with common optional fields.""" + return RackType( + manufacturer="Example Manufacturer", + model="Model X", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + form_factor="2-post-frame", + width=1, + u_height=1, + starting_unit=1, + desc_units=True, + outer_width=1, + outer_depth=1, + outer_unit="in", + weight=1.0, + max_weight=1, + weight_unit="g", + mounting_depth=1, + comments="Example comments", + outer_height=1, + ) + + +def rack_type_explicit() -> RackType: + """Create a RackType with fully nested objects and all common fields.""" + return RackType( + manufacturer=Manufacturer( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + model="Model X", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + form_factor="2-post-frame", + width=1, + u_height=1, + starting_unit=1, + desc_units=True, + outer_width=1, + outer_depth=1, + outer_unit="in", + weight=1.0, + max_weight=1, + weight_unit="g", + mounting_depth=1, + outer_height=1, + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/rear_port.py b/docs/examples/rear_port.py new file mode 100644 index 0000000..30785b9 --- /dev/null +++ b/docs/examples/rear_port.py @@ -0,0 +1,200 @@ +""" +RearPort entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting RearPort entities: +- rear_port_minimal: Required fields only +- rear_port_extended: Common optional fields +- rear_port_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Module, + ModuleBay, + ModuleType, + Owner, + OwnerGroup, + RearPort, + Site, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "rear_port-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a RearPort entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + rear_port = rear_port_minimal() + # rear_port = rear_port_extended() + # rear_port = rear_port_explicit() + + response = client.ingest(entities=[Entity(rear_port=rear_port)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("RearPort ingested successfully") + + +def rear_port_minimal() -> RearPort: + """Create a RearPort with only required fields using flat strings.""" + return RearPort( + device="Example Device", # flat string -> Device + name="Example Name", + type="110-punch", + metadata={"source": "example"}, + ) + + +def rear_port_extended() -> RearPort: + """Create a RearPort with common optional fields.""" + return RearPort( + device="Example Device", + name="Example Name", + type="110-punch", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + color="0000ff", + label="Example Label", + positions=1, + mark_connected=True, + ) + + +def rear_port_explicit() -> RearPort: + """Create a RearPort with fully nested objects and all common fields.""" + return RearPort( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="110-punch", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + color="0000ff", + label="Example Label", + positions=1, + mark_connected=True, + module=Module( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + module_bay=ModuleBay( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + module_type=ModuleType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/region.py b/docs/examples/region.py new file mode 100644 index 0000000..4a22cee --- /dev/null +++ b/docs/examples/region.py @@ -0,0 +1,92 @@ +""" +Region entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Region entities: +- region_minimal: Required fields only +- region_extended: Common optional fields +- region_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Region, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "region-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Region entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + region = region_minimal() + # region = region_extended() + # region = region_explicit() + + response = client.ingest(entities=[Entity(region=region)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Region ingested successfully") + + +def region_minimal() -> Region: + """Create a Region with only required fields using flat strings.""" + return Region( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def region_extended() -> Region: + """Create a Region with common optional fields.""" + return Region( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def region_explicit() -> Region: + """Create a Region with fully nested objects and all common fields.""" + return Region( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + parent=Region( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/rir.py b/docs/examples/rir.py new file mode 100644 index 0000000..3f4e91a --- /dev/null +++ b/docs/examples/rir.py @@ -0,0 +1,91 @@ +""" +RIR entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting RIR entities: +- rir_minimal: Required fields only +- rir_extended: Common optional fields +- rir_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + RIR, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "rir-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a RIR entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + rir = rir_minimal() + # rir = rir_extended() + # rir = rir_explicit() + + response = client.ingest(entities=[Entity(rir=rir)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("RIR ingested successfully") + + +def rir_minimal() -> RIR: + """Create a RIR with only required fields using flat strings.""" + return RIR( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def rir_extended() -> RIR: + """Create a RIR with common optional fields.""" + return RIR( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + is_private=True, + comments="Example comments", + ) + + +def rir_explicit() -> RIR: + """Create a RIR with fully nested objects and all common fields.""" + return RIR( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + is_private=True, + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/role.py b/docs/examples/role.py new file mode 100644 index 0000000..d53db0b --- /dev/null +++ b/docs/examples/role.py @@ -0,0 +1,91 @@ +""" +Role entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Role entities: +- role_minimal: Required fields only +- role_extended: Common optional fields +- role_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Role, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "role-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Role entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + role = role_minimal() + # role = role_extended() + # role = role_explicit() + + response = client.ingest(entities=[Entity(role=role)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Role ingested successfully") + + +def role_minimal() -> Role: + """Create a Role with only required fields using flat strings.""" + return Role( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def role_extended() -> Role: + """Create a Role with common optional fields.""" + return Role( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + weight=1, + comments="Example comments", + ) + + +def role_explicit() -> Role: + """Create a Role with fully nested objects and all common fields.""" + return Role( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + weight=1, + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/route_target.py b/docs/examples/route_target.py new file mode 100644 index 0000000..3935be3 --- /dev/null +++ b/docs/examples/route_target.py @@ -0,0 +1,91 @@ +""" +RouteTarget entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting RouteTarget entities: +- route_target_minimal: Required fields only +- route_target_extended: Common optional fields +- route_target_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + RouteTarget, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "route_target-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a RouteTarget entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + route_target = route_target_minimal() + # route_target = route_target_extended() + # route_target = route_target_explicit() + + response = client.ingest(entities=[Entity(route_target=route_target)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("RouteTarget ingested successfully") + + +def route_target_minimal() -> RouteTarget: + """Create a RouteTarget with only required fields using flat strings.""" + return RouteTarget( + name="Example Name", + metadata={"source": "example"}, + ) + + +def route_target_extended() -> RouteTarget: + """Create a RouteTarget with common optional fields.""" + return RouteTarget( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + tenant="Example Tenant", + comments="Example comments", + ) + + +def route_target_explicit() -> RouteTarget: + """Create a RouteTarget with fully nested objects and all common fields.""" + return RouteTarget( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/service.py b/docs/examples/service.py new file mode 100644 index 0000000..2b00f73 --- /dev/null +++ b/docs/examples/service.py @@ -0,0 +1,124 @@ +""" +Service entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Service entities: +- service_minimal: Required fields only +- service_extended: Common optional fields +- service_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Owner, + OwnerGroup, + Service, + Site, + Tag, + VirtualMachine, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "service-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Service entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + service = service_minimal() + # service = service_extended() + # service = service_explicit() + + response = client.ingest(entities=[Entity(service=service)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Service ingested successfully") + + +def service_minimal() -> Service: + """Create a Service with only required fields using flat strings.""" + return Service( + name="Example Name", + metadata={"source": "example"}, + ) + + +def service_extended() -> Service: + """Create a Service with common optional fields.""" + return Service( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + device="Example Device", + protocol="sctp", + comments="Example comments", + ) + + +def service_explicit() -> Service: + """Create a Service with fully nested objects and all common fields.""" + return Service( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + protocol="sctp", + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + virtual_machine=VirtualMachine( + name="Example Name", status="active", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/site.py b/docs/examples/site.py new file mode 100644 index 0000000..8a1d7f4 --- /dev/null +++ b/docs/examples/site.py @@ -0,0 +1,117 @@ +""" +Site entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Site entities: +- site_minimal: Required fields only +- site_extended: Common optional fields +- site_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Region, + Site, + SiteGroup, + Tag, + Tenant, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "site-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Site entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + site = site_minimal() + # site = site_extended() + # site = site_explicit() + + response = client.ingest(entities=[Entity(site=site)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Site ingested successfully") + + +def site_minimal() -> Site: + """Create a Site with only required fields using flat strings.""" + return Site( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def site_extended() -> Site: + """Create a Site with common optional fields.""" + return Site( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + region="Example Region", + tenant="Example Tenant", + facility="Example Facility", + time_zone="Example Time Zone", + physical_address="Example Physical Address", + shipping_address="Example Shipping Address", + latitude=1.0, + longitude=1.0, + comments="Example comments", + ) + + +def site_explicit() -> Site: + """Create a Site with fully nested objects and all common fields.""" + return Site( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + facility="Example Facility", + time_zone="Example Time Zone", + physical_address="Example Physical Address", + shipping_address="Example Shipping Address", + latitude=1.0, + longitude=1.0, + region=Region( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + group=SiteGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/site_group.py b/docs/examples/site_group.py new file mode 100644 index 0000000..6b61284 --- /dev/null +++ b/docs/examples/site_group.py @@ -0,0 +1,92 @@ +""" +SiteGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting SiteGroup entities: +- site_group_minimal: Required fields only +- site_group_extended: Common optional fields +- site_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + SiteGroup, + Tag, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "site_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a SiteGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + site_group = site_group_minimal() + # site_group = site_group_extended() + # site_group = site_group_explicit() + + response = client.ingest(entities=[Entity(site_group=site_group)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("SiteGroup ingested successfully") + + +def site_group_minimal() -> SiteGroup: + """Create a SiteGroup with only required fields using flat strings.""" + return SiteGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def site_group_extended() -> SiteGroup: + """Create a SiteGroup with common optional fields.""" + return SiteGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def site_group_explicit() -> SiteGroup: + """Create a SiteGroup with fully nested objects and all common fields.""" + return SiteGroup( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + parent=SiteGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/tag.py b/docs/examples/tag.py new file mode 100644 index 0000000..4b36404 --- /dev/null +++ b/docs/examples/tag.py @@ -0,0 +1,78 @@ +""" +Tag entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Tag entities: +- tag_minimal: Required fields only +- tag_extended: Common optional fields +- tag_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "tag-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Tag entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + tag = tag_minimal() + # tag = tag_extended() + # tag = tag_explicit() + + response = client.ingest(entities=[Entity(tag=tag)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Tag ingested successfully") + + +def tag_minimal() -> Tag: + """Create a Tag with only required fields using flat strings.""" + return Tag( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def tag_extended() -> Tag: + """Create a Tag with common optional fields.""" + return Tag( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + color="0000ff", + weight=1, + ) + + +def tag_explicit() -> Tag: + """Create a Tag with fully nested objects and all common fields.""" + return Tag( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + color="0000ff", + weight=1, + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/tenant.py b/docs/examples/tenant.py new file mode 100644 index 0000000..b23e6c6 --- /dev/null +++ b/docs/examples/tenant.py @@ -0,0 +1,93 @@ +""" +Tenant entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Tenant entities: +- tenant_minimal: Required fields only +- tenant_extended: Common optional fields +- tenant_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Tag, + Tenant, + TenantGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "tenant-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Tenant entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + tenant = tenant_minimal() + # tenant = tenant_extended() + # tenant = tenant_explicit() + + response = client.ingest(entities=[Entity(tenant=tenant)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Tenant ingested successfully") + + +def tenant_minimal() -> Tenant: + """Create a Tenant with only required fields using flat strings.""" + return Tenant( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def tenant_extended() -> Tenant: + """Create a Tenant with common optional fields.""" + return Tenant( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def tenant_explicit() -> Tenant: + """Create a Tenant with fully nested objects and all common fields.""" + return Tenant( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + group=TenantGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/tenant_group.py b/docs/examples/tenant_group.py new file mode 100644 index 0000000..07d9bd9 --- /dev/null +++ b/docs/examples/tenant_group.py @@ -0,0 +1,92 @@ +""" +TenantGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting TenantGroup entities: +- tenant_group_minimal: Required fields only +- tenant_group_extended: Common optional fields +- tenant_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Tag, + TenantGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "tenant_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a TenantGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + tenant_group = tenant_group_minimal() + # tenant_group = tenant_group_extended() + # tenant_group = tenant_group_explicit() + + response = client.ingest(entities=[Entity(tenant_group=tenant_group)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("TenantGroup ingested successfully") + + +def tenant_group_minimal() -> TenantGroup: + """Create a TenantGroup with only required fields using flat strings.""" + return TenantGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def tenant_group_extended() -> TenantGroup: + """Create a TenantGroup with common optional fields.""" + return TenantGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def tenant_group_explicit() -> TenantGroup: + """Create a TenantGroup with fully nested objects and all common fields.""" + return TenantGroup( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + parent=TenantGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/tunnel.py b/docs/examples/tunnel.py new file mode 100644 index 0000000..44a9512 --- /dev/null +++ b/docs/examples/tunnel.py @@ -0,0 +1,117 @@ +""" +Tunnel entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting Tunnel entities: +- tunnel_minimal: Required fields only +- tunnel_extended: Common optional fields +- tunnel_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + IKEPolicy, + IPSecPolicy, + IPSecProfile, + Owner, + OwnerGroup, + Tag, + Tenant, + Tunnel, + TunnelGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "tunnel-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a Tunnel entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + tunnel = tunnel_minimal() + # tunnel = tunnel_extended() + # tunnel = tunnel_explicit() + + response = client.ingest(entities=[Entity(tunnel=tunnel)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("Tunnel ingested successfully") + + +def tunnel_minimal() -> Tunnel: + """Create a Tunnel with only required fields using flat strings.""" + return Tunnel( + name="Example Name", + status="active", + encapsulation="gre", + metadata={"source": "example"}, + ) + + +def tunnel_extended() -> Tunnel: + """Create a Tunnel with common optional fields.""" + return Tunnel( + name="Example Name", + status="active", + encapsulation="gre", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + tenant="Example Tenant", + tunnel_id=1, + comments="Example comments", + ) + + +def tunnel_explicit() -> Tunnel: + """Create a Tunnel with fully nested objects and all common fields.""" + return Tunnel( + name="Example Name", + status="active", + encapsulation="gre", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + tunnel_id=1, + group=TunnelGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + ipsec_profile=IPSecProfile( + name="Example Name", + mode="Example Mode", + ike_policy=IKEPolicy( + name="Example Name", version=1, metadata={"source": "example"} + ), + ipsec_policy=IPSecPolicy( + name="Example Name", metadata={"source": "example"} + ), + metadata={"source": "example"}, + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/tunnel_group.py b/docs/examples/tunnel_group.py new file mode 100644 index 0000000..a2cf2ee --- /dev/null +++ b/docs/examples/tunnel_group.py @@ -0,0 +1,89 @@ +""" +TunnelGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting TunnelGroup entities: +- tunnel_group_minimal: Required fields only +- tunnel_group_extended: Common optional fields +- tunnel_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Tag, + TunnelGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "tunnel_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a TunnelGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + tunnel_group = tunnel_group_minimal() + # tunnel_group = tunnel_group_extended() + # tunnel_group = tunnel_group_explicit() + + response = client.ingest(entities=[Entity(tunnel_group=tunnel_group)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("TunnelGroup ingested successfully") + + +def tunnel_group_minimal() -> TunnelGroup: + """Create a TunnelGroup with only required fields using flat strings.""" + return TunnelGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def tunnel_group_extended() -> TunnelGroup: + """Create a TunnelGroup with common optional fields.""" + return TunnelGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def tunnel_group_explicit() -> TunnelGroup: + """Create a TunnelGroup with fully nested objects and all common fields.""" + return TunnelGroup( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/tunnel_termination.py b/docs/examples/tunnel_termination.py new file mode 100644 index 0000000..e34ade2 --- /dev/null +++ b/docs/examples/tunnel_termination.py @@ -0,0 +1,90 @@ +""" +TunnelTermination entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting TunnelTermination entities: +- tunnel_termination_minimal: Required fields only +- tunnel_termination_extended: Common optional fields +- tunnel_termination_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + IPAddress, + Tag, + Tunnel, + TunnelTermination, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "tunnel_termination-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a TunnelTermination entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + tunnel_termination = tunnel_termination_minimal() + # tunnel_termination = tunnel_termination_extended() + # tunnel_termination = tunnel_termination_explicit() + + response = client.ingest( + entities=[Entity(tunnel_termination=tunnel_termination)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("TunnelTermination ingested successfully") + + +def tunnel_termination_minimal() -> TunnelTermination: + """Create a TunnelTermination with only required fields using flat strings.""" + return TunnelTermination( + tunnel="Example Tunnel", # flat string -> Tunnel + role="hub", + metadata={"source": "example"}, + ) + + +def tunnel_termination_extended() -> TunnelTermination: + """Create a TunnelTermination with common optional fields.""" + return TunnelTermination( + tunnel="Example Tunnel", + role="hub", + metadata={"source": "example", "custom_key": "custom_value"}, + ) + + +def tunnel_termination_explicit() -> TunnelTermination: + """Create a TunnelTermination with fully nested objects and all common fields.""" + return TunnelTermination( + tunnel=Tunnel( + name="Example Name", + status="active", + encapsulation="Example Encapsulation", + metadata={"source": "example"}, + ), + role="hub", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + outside_ip=IPAddress( + address="192.0.2.1/32", status="active", metadata={"source": "example"} + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/virtual_chassis.py b/docs/examples/virtual_chassis.py new file mode 100644 index 0000000..32de876 --- /dev/null +++ b/docs/examples/virtual_chassis.py @@ -0,0 +1,119 @@ +""" +VirtualChassis entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VirtualChassis entities: +- virtual_chassis_minimal: Required fields only +- virtual_chassis_extended: Common optional fields +- virtual_chassis_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Manufacturer, + Owner, + OwnerGroup, + Site, + Tag, + VirtualChassis, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "virtual_chassis-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VirtualChassis entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + virtual_chassis = virtual_chassis_minimal() + # virtual_chassis = virtual_chassis_extended() + # virtual_chassis = virtual_chassis_explicit() + + response = client.ingest(entities=[Entity(virtual_chassis=virtual_chassis)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VirtualChassis ingested successfully") + + +def virtual_chassis_minimal() -> VirtualChassis: + """Create a VirtualChassis with only required fields using flat strings.""" + return VirtualChassis( + name="Example Name", + metadata={"source": "example"}, + ) + + +def virtual_chassis_extended() -> VirtualChassis: + """Create a VirtualChassis with common optional fields.""" + return VirtualChassis( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + domain="Example Domain", + comments="Example comments", + ) + + +def virtual_chassis_explicit() -> VirtualChassis: + """Create a VirtualChassis with fully nested objects and all common fields.""" + return VirtualChassis( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + domain="Example Domain", + master=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/virtual_circuit.py b/docs/examples/virtual_circuit.py new file mode 100644 index 0000000..55c2286 --- /dev/null +++ b/docs/examples/virtual_circuit.py @@ -0,0 +1,121 @@ +""" +VirtualCircuit entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VirtualCircuit entities: +- virtual_circuit_minimal: Required fields only +- virtual_circuit_extended: Common optional fields +- virtual_circuit_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Provider, + ProviderAccount, + ProviderNetwork, + Tag, + Tenant, + VirtualCircuit, + VirtualCircuitType, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "virtual_circuit-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VirtualCircuit entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + virtual_circuit = virtual_circuit_minimal() + # virtual_circuit = virtual_circuit_extended() + # virtual_circuit = virtual_circuit_explicit() + + response = client.ingest(entities=[Entity(virtual_circuit=virtual_circuit)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VirtualCircuit ingested successfully") + + +def virtual_circuit_minimal() -> VirtualCircuit: + """Create a VirtualCircuit with only required fields using flat strings.""" + return VirtualCircuit( + cid="CID-001", + provider_network="Example Provider Network", # flat string -> ProviderNetwork + type="Example Type", # flat string -> VirtualCircuitType + metadata={"source": "example"}, + ) + + +def virtual_circuit_extended() -> VirtualCircuit: + """Create a VirtualCircuit with common optional fields.""" + return VirtualCircuit( + cid="CID-001", + provider_network="Example Provider Network", + type="Example Type", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + tenant="Example Tenant", + comments="Example comments", + ) + + +def virtual_circuit_explicit() -> VirtualCircuit: + """Create a VirtualCircuit with fully nested objects and all common fields.""" + return VirtualCircuit( + cid="CID-001", + provider_network=ProviderNetwork( + provider=Provider( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + name="Example Name", + metadata={"source": "example"}, + ), + type=VirtualCircuitType( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + provider_account=ProviderAccount( + provider=Provider( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + account="Example Account", + metadata={"source": "example"}, + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/virtual_circuit_termination.py b/docs/examples/virtual_circuit_termination.py new file mode 100644 index 0000000..907794b --- /dev/null +++ b/docs/examples/virtual_circuit_termination.py @@ -0,0 +1,143 @@ +""" +VirtualCircuitTermination entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VirtualCircuitTermination entities: +- virtual_circuit_termination_minimal: Required fields only +- virtual_circuit_termination_extended: Common optional fields +- virtual_circuit_termination_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Interface, + Manufacturer, + Provider, + ProviderNetwork, + Site, + Tag, + VirtualCircuit, + VirtualCircuitTermination, + VirtualCircuitType, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "virtual_circuit_termination-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VirtualCircuitTermination entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + virtual_circuit_termination = virtual_circuit_termination_minimal() + # virtual_circuit_termination = virtual_circuit_termination_extended() + # virtual_circuit_termination = virtual_circuit_termination_explicit() + + response = client.ingest( + entities=[Entity(virtual_circuit_termination=virtual_circuit_termination)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VirtualCircuitTermination ingested successfully") + + +def virtual_circuit_termination_minimal() -> VirtualCircuitTermination: + """Create a VirtualCircuitTermination with only required fields using flat strings.""" + return VirtualCircuitTermination( + virtual_circuit="Example Virtual Circuit", # flat string -> VirtualCircuit + interface="Example Interface", # flat string -> Interface + metadata={"source": "example"}, + ) + + +def virtual_circuit_termination_extended() -> VirtualCircuitTermination: + """Create a VirtualCircuitTermination with common optional fields.""" + return VirtualCircuitTermination( + virtual_circuit="Example Virtual Circuit", + interface="Example Interface", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + role="hub", + ) + + +def virtual_circuit_termination_explicit() -> VirtualCircuitTermination: + """Create a VirtualCircuitTermination with fully nested objects and all common fields.""" + return VirtualCircuitTermination( + virtual_circuit=VirtualCircuit( + cid="CID-001", + provider_network=ProviderNetwork( + provider=Provider( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + name="Example Name", + metadata={"source": "example"}, + ), + type=VirtualCircuitType( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + interface=Interface( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="Example Type", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + role="hub", + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/virtual_circuit_type.py b/docs/examples/virtual_circuit_type.py new file mode 100644 index 0000000..3472a99 --- /dev/null +++ b/docs/examples/virtual_circuit_type.py @@ -0,0 +1,93 @@ +""" +VirtualCircuitType entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VirtualCircuitType entities: +- virtual_circuit_type_minimal: Required fields only +- virtual_circuit_type_extended: Common optional fields +- virtual_circuit_type_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Tag, + VirtualCircuitType, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "virtual_circuit_type-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VirtualCircuitType entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + virtual_circuit_type = virtual_circuit_type_minimal() + # virtual_circuit_type = virtual_circuit_type_extended() + # virtual_circuit_type = virtual_circuit_type_explicit() + + response = client.ingest( + entities=[Entity(virtual_circuit_type=virtual_circuit_type)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VirtualCircuitType ingested successfully") + + +def virtual_circuit_type_minimal() -> VirtualCircuitType: + """Create a VirtualCircuitType with only required fields using flat strings.""" + return VirtualCircuitType( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def virtual_circuit_type_extended() -> VirtualCircuitType: + """Create a VirtualCircuitType with common optional fields.""" + return VirtualCircuitType( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + color="0000ff", + comments="Example comments", + ) + + +def virtual_circuit_type_explicit() -> VirtualCircuitType: + """Create a VirtualCircuitType with fully nested objects and all common fields.""" + return VirtualCircuitType( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + color="0000ff", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/virtual_device_context.py b/docs/examples/virtual_device_context.py new file mode 100644 index 0000000..de8e4e4 --- /dev/null +++ b/docs/examples/virtual_device_context.py @@ -0,0 +1,138 @@ +""" +VirtualDeviceContext entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VirtualDeviceContext entities: +- virtual_device_context_minimal: Required fields only +- virtual_device_context_extended: Common optional fields +- virtual_device_context_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + IPAddress, + Manufacturer, + Owner, + OwnerGroup, + Site, + Tag, + Tenant, + VirtualDeviceContext, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "virtual_device_context-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VirtualDeviceContext entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + virtual_device_context = virtual_device_context_minimal() + # virtual_device_context = virtual_device_context_extended() + # virtual_device_context = virtual_device_context_explicit() + + response = client.ingest( + entities=[Entity(virtual_device_context=virtual_device_context)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VirtualDeviceContext ingested successfully") + + +def virtual_device_context_minimal() -> VirtualDeviceContext: + """Create a VirtualDeviceContext with only required fields using flat strings.""" + return VirtualDeviceContext( + name="Example Name", + device="Example Device", # flat string -> Device + status="active", + metadata={"source": "example"}, + ) + + +def virtual_device_context_extended() -> VirtualDeviceContext: + """Create a VirtualDeviceContext with common optional fields.""" + return VirtualDeviceContext( + name="Example Name", + device="Example Device", + status="active", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + identifier=1, + tenant="Example Tenant", + comments="Example comments", + ) + + +def virtual_device_context_explicit() -> VirtualDeviceContext: + """Create a VirtualDeviceContext with fully nested objects and all common fields.""" + return VirtualDeviceContext( + name="Example Name", + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + identifier=1, + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + primary_ip4=IPAddress( + address="192.0.2.1/32", status="active", metadata={"source": "example"} + ), + primary_ip6=IPAddress( + address="192.0.2.1/32", status="active", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/virtual_disk.py b/docs/examples/virtual_disk.py new file mode 100644 index 0000000..a0feca2 --- /dev/null +++ b/docs/examples/virtual_disk.py @@ -0,0 +1,93 @@ +""" +VirtualDisk entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VirtualDisk entities: +- virtual_disk_minimal: Required fields only +- virtual_disk_extended: Common optional fields +- virtual_disk_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Tag, + VirtualDisk, + VirtualMachine, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "virtual_disk-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VirtualDisk entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + virtual_disk = virtual_disk_minimal() + # virtual_disk = virtual_disk_extended() + # virtual_disk = virtual_disk_explicit() + + response = client.ingest(entities=[Entity(virtual_disk=virtual_disk)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VirtualDisk ingested successfully") + + +def virtual_disk_minimal() -> VirtualDisk: + """Create a VirtualDisk with only required fields using flat strings.""" + return VirtualDisk( + virtual_machine="Example Virtual Machine", # flat string -> VirtualMachine + name="Example Name", + size=1, + metadata={"source": "example"}, + ) + + +def virtual_disk_extended() -> VirtualDisk: + """Create a VirtualDisk with common optional fields.""" + return VirtualDisk( + virtual_machine="Example Virtual Machine", + name="Example Name", + size=1, + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + ) + + +def virtual_disk_explicit() -> VirtualDisk: + """Create a VirtualDisk with fully nested objects and all common fields.""" + return VirtualDisk( + virtual_machine=VirtualMachine( + name="Example Name", status="active", metadata={"source": "example"} + ), + name="Example Name", + size=1, + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/virtual_machine.py b/docs/examples/virtual_machine.py new file mode 100644 index 0000000..77b2d4e --- /dev/null +++ b/docs/examples/virtual_machine.py @@ -0,0 +1,172 @@ +""" +VirtualMachine entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VirtualMachine entities: +- virtual_machine_minimal: Required fields only +- virtual_machine_extended: Common optional fields +- virtual_machine_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Cluster, + ClusterType, + Device, + DeviceRole, + DeviceType, + Entity, + IPAddress, + Manufacturer, + Owner, + OwnerGroup, + Platform, + Site, + Tag, + Tenant, + VirtualMachine, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "virtual_machine-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VirtualMachine entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + virtual_machine = virtual_machine_minimal() + # virtual_machine = virtual_machine_extended() + # virtual_machine = virtual_machine_explicit() + + response = client.ingest(entities=[Entity(virtual_machine=virtual_machine)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VirtualMachine ingested successfully") + + +def virtual_machine_minimal() -> VirtualMachine: + """Create a VirtualMachine with only required fields using flat strings.""" + return VirtualMachine( + name="Example Name", + metadata={"source": "example"}, + ) + + +def virtual_machine_extended() -> VirtualMachine: + """Create a VirtualMachine with common optional fields.""" + return VirtualMachine( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + serial="SN-001234", + description="Example description", + site="Example Site", + cluster="Example Cluster", + device="Example Device", + role="Example Role", + tenant="Example Tenant", + platform="Example Platform", + vcpus=1.0, + memory=1, + disk=1, + comments="Example comments", + start_on_boot="laststate", + ) + + +def virtual_machine_explicit() -> VirtualMachine: + """Create a VirtualMachine with fully nested objects and all common fields.""" + return VirtualMachine( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + serial="SN-001234", + description="Example description", + comments="Example comments", + vcpus=1.0, + memory=1, + disk=1, + start_on_boot="laststate", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + cluster=Cluster( + name="Example Name", + type=ClusterType( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + status="active", + metadata={"source": "example"}, + ), + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + platform=Platform( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + primary_ip4=IPAddress( + address="192.0.2.1/32", status="active", metadata={"source": "example"} + ), + primary_ip6=IPAddress( + address="192.0.2.1/32", status="active", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/vlan.py b/docs/examples/vlan.py new file mode 100644 index 0000000..6e05974 --- /dev/null +++ b/docs/examples/vlan.py @@ -0,0 +1,118 @@ +""" +VLAN entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VLAN entities: +- vlan_minimal: Required fields only +- vlan_extended: Common optional fields +- vlan_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Role, + Site, + Tag, + Tenant, + VLAN, + VLANGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "vlan-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VLAN entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + vlan = vlan_minimal() + # vlan = vlan_extended() + # vlan = vlan_explicit() + + response = client.ingest(entities=[Entity(vlan=vlan)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VLAN ingested successfully") + + +def vlan_minimal() -> VLAN: + """Create a VLAN with only required fields using flat strings.""" + return VLAN( + vid=1, + name="Example Name", + metadata={"source": "example"}, + ) + + +def vlan_extended() -> VLAN: + """Create a VLAN with common optional fields.""" + return VLAN( + vid=1, + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + site="Example Site", + tenant="Example Tenant", + role="Example Role", + qinq_role="cvlan", + comments="Example comments", + ) + + +def vlan_explicit() -> VLAN: + """Create a VLAN with fully nested objects and all common fields.""" + return VLAN( + vid=1, + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + qinq_role="cvlan", + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + group=VLANGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + role=Role( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + qinq_svlan=VLAN( + vid=1, name="Example Name", status="active", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/vlan_group.py b/docs/examples/vlan_group.py new file mode 100644 index 0000000..2c75c61 --- /dev/null +++ b/docs/examples/vlan_group.py @@ -0,0 +1,94 @@ +""" +VLANGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VLANGroup entities: +- vlan_group_minimal: Required fields only +- vlan_group_extended: Common optional fields +- vlan_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Tag, + Tenant, + VLANGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "vlan_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VLANGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + vlan_group = vlan_group_minimal() + # vlan_group = vlan_group_extended() + # vlan_group = vlan_group_explicit() + + response = client.ingest(entities=[Entity(vlan_group=vlan_group)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VLANGroup ingested successfully") + + +def vlan_group_minimal() -> VLANGroup: + """Create a VLANGroup with only required fields using flat strings.""" + return VLANGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def vlan_group_extended() -> VLANGroup: + """Create a VLANGroup with common optional fields.""" + return VLANGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + tenant="Example Tenant", + comments="Example comments", + ) + + +def vlan_group_explicit() -> VLANGroup: + """Create a VLANGroup with fully nested objects and all common fields.""" + return VLANGroup( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/vlan_translation_policy.py b/docs/examples/vlan_translation_policy.py new file mode 100644 index 0000000..1132b85 --- /dev/null +++ b/docs/examples/vlan_translation_policy.py @@ -0,0 +1,86 @@ +""" +VLANTranslationPolicy entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VLANTranslationPolicy entities: +- vlan_translation_policy_minimal: Required fields only +- vlan_translation_policy_extended: Common optional fields +- vlan_translation_policy_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + VLANTranslationPolicy, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "vlan_translation_policy-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VLANTranslationPolicy entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + vlan_translation_policy = vlan_translation_policy_minimal() + # vlan_translation_policy = vlan_translation_policy_extended() + # vlan_translation_policy = vlan_translation_policy_explicit() + + response = client.ingest( + entities=[Entity(vlan_translation_policy=vlan_translation_policy)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VLANTranslationPolicy ingested successfully") + + +def vlan_translation_policy_minimal() -> VLANTranslationPolicy: + """Create a VLANTranslationPolicy with only required fields using flat strings.""" + return VLANTranslationPolicy( + name="Example Name", + metadata={"source": "example"}, + ) + + +def vlan_translation_policy_extended() -> VLANTranslationPolicy: + """Create a VLANTranslationPolicy with common optional fields.""" + return VLANTranslationPolicy( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def vlan_translation_policy_explicit() -> VLANTranslationPolicy: + """Create a VLANTranslationPolicy with fully nested objects and all common fields.""" + return VLANTranslationPolicy( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/vlan_translation_rule.py b/docs/examples/vlan_translation_rule.py new file mode 100644 index 0000000..cb56ad4 --- /dev/null +++ b/docs/examples/vlan_translation_rule.py @@ -0,0 +1,86 @@ +""" +VLANTranslationRule entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VLANTranslationRule entities: +- vlan_translation_rule_minimal: Required fields only +- vlan_translation_rule_extended: Common optional fields +- vlan_translation_rule_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + VLANTranslationPolicy, + VLANTranslationRule, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "vlan_translation_rule-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VLANTranslationRule entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + vlan_translation_rule = vlan_translation_rule_minimal() + # vlan_translation_rule = vlan_translation_rule_extended() + # vlan_translation_rule = vlan_translation_rule_explicit() + + response = client.ingest( + entities=[Entity(vlan_translation_rule=vlan_translation_rule)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VLANTranslationRule ingested successfully") + + +def vlan_translation_rule_minimal() -> VLANTranslationRule: + """Create a VLANTranslationRule with only required fields using flat strings.""" + return VLANTranslationRule( + policy="Example Policy", # flat string -> VLANTranslationPolicy + local_vid=1, + remote_vid=1, + metadata={"source": "example"}, + ) + + +def vlan_translation_rule_extended() -> VLANTranslationRule: + """Create a VLANTranslationRule with common optional fields.""" + return VLANTranslationRule( + policy="Example Policy", + local_vid=1, + remote_vid=1, + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + ) + + +def vlan_translation_rule_explicit() -> VLANTranslationRule: + """Create a VLANTranslationRule with fully nested objects and all common fields.""" + return VLANTranslationRule( + policy=VLANTranslationPolicy( + name="Example Name", metadata={"source": "example"} + ), + local_vid=1, + remote_vid=1, + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/vm_interface.py b/docs/examples/vm_interface.py new file mode 100644 index 0000000..c24c1a8 --- /dev/null +++ b/docs/examples/vm_interface.py @@ -0,0 +1,127 @@ +""" +VMInterface entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VMInterface entities: +- vm_interface_minimal: Required fields only +- vm_interface_extended: Common optional fields +- vm_interface_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + MACAddress, + Owner, + OwnerGroup, + Tag, + VLAN, + VLANTranslationPolicy, + VMInterface, + VRF, + VirtualMachine, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "vm_interface-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VMInterface entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + vm_interface = vm_interface_minimal() + # vm_interface = vm_interface_extended() + # vm_interface = vm_interface_explicit() + + response = client.ingest(entities=[Entity(vm_interface=vm_interface)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VMInterface ingested successfully") + + +def vm_interface_minimal() -> VMInterface: + """Create a VMInterface with only required fields using flat strings.""" + return VMInterface( + virtual_machine="Example Virtual Machine", # flat string -> VirtualMachine + name="Example Name", + metadata={"source": "example"}, + ) + + +def vm_interface_extended() -> VMInterface: + """Create a VMInterface with common optional fields.""" + return VMInterface( + virtual_machine="Example Virtual Machine", + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + enabled=True, + mtu=1, + mode="access", + ) + + +def vm_interface_explicit() -> VMInterface: + """Create a VMInterface with fully nested objects and all common fields.""" + return VMInterface( + virtual_machine=VirtualMachine( + name="Example Name", status="active", metadata={"source": "example"} + ), + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + enabled=True, + mtu=1, + mode="access", + parent=VMInterface( + virtual_machine=VirtualMachine( + name="Example Name", status="active", metadata={"source": "example"} + ), + name="Example Name", + metadata={"source": "example"}, + ), + bridge=VMInterface( + virtual_machine=VirtualMachine( + name="Example Name", status="active", metadata={"source": "example"} + ), + name="Example Name", + metadata={"source": "example"}, + ), + primary_mac_address=MACAddress( + mac_address="00:11:22:33:44:55", metadata={"source": "example"} + ), + untagged_vlan=VLAN( + vid=1, name="Example Name", status="active", metadata={"source": "example"} + ), + qinq_svlan=VLAN( + vid=1, name="Example Name", status="active", metadata={"source": "example"} + ), + vlan_translation_policy=VLANTranslationPolicy( + name="Example Name", metadata={"source": "example"} + ), + vrf=VRF(name="Example Name", metadata={"source": "example"}), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/vrf.py b/docs/examples/vrf.py new file mode 100644 index 0000000..80a3270 --- /dev/null +++ b/docs/examples/vrf.py @@ -0,0 +1,95 @@ +""" +VRF entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting VRF entities: +- vrf_minimal: Required fields only +- vrf_extended: Common optional fields +- vrf_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Tag, + Tenant, + VRF, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "vrf-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a VRF entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + vrf = vrf_minimal() + # vrf = vrf_extended() + # vrf = vrf_explicit() + + response = client.ingest(entities=[Entity(vrf=vrf)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("VRF ingested successfully") + + +def vrf_minimal() -> VRF: + """Create a VRF with only required fields using flat strings.""" + return VRF( + name="Example Name", + metadata={"source": "example"}, + ) + + +def vrf_extended() -> VRF: + """Create a VRF with common optional fields.""" + return VRF( + name="Example Name", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + rd="Example Rd", + tenant="Example Tenant", + enforce_unique=True, + comments="Example comments", + ) + + +def vrf_explicit() -> VRF: + """Create a VRF with fully nested objects and all common fields.""" + return VRF( + name="Example Name", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + rd="Example Rd", + enforce_unique=True, + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/wireless_lan.py b/docs/examples/wireless_lan.py new file mode 100644 index 0000000..0e21827 --- /dev/null +++ b/docs/examples/wireless_lan.py @@ -0,0 +1,107 @@ +""" +WirelessLAN entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting WirelessLAN entities: +- wireless_lan_minimal: Required fields only +- wireless_lan_extended: Common optional fields +- wireless_lan_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Tag, + Tenant, + VLAN, + WirelessLAN, + WirelessLANGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "wireless_lan-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a WirelessLAN entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + wireless_lan = wireless_lan_minimal() + # wireless_lan = wireless_lan_extended() + # wireless_lan = wireless_lan_explicit() + + response = client.ingest(entities=[Entity(wireless_lan=wireless_lan)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("WirelessLAN ingested successfully") + + +def wireless_lan_minimal() -> WirelessLAN: + """Create a WirelessLAN with only required fields using flat strings.""" + return WirelessLAN( + ssid="ExampleSSID", + metadata={"source": "example"}, + ) + + +def wireless_lan_extended() -> WirelessLAN: + """Create a WirelessLAN with common optional fields.""" + return WirelessLAN( + ssid="ExampleSSID", + metadata={"source": "example", "custom_key": "custom_value"}, + status="active", + description="Example description", + tenant="Example Tenant", + auth_type="open", + auth_cipher="aes", + auth_psk="Example Auth Psk", + comments="Example comments", + ) + + +def wireless_lan_explicit() -> WirelessLAN: + """Create a WirelessLAN with fully nested objects and all common fields.""" + return WirelessLAN( + ssid="ExampleSSID", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="active", + description="Example description", + comments="Example comments", + auth_type="open", + auth_cipher="aes", + auth_psk="Example Auth Psk", + group=WirelessLANGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + vlan=VLAN( + vid=1, name="Example Name", status="active", metadata={"source": "example"} + ), + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/wireless_lan_group.py b/docs/examples/wireless_lan_group.py new file mode 100644 index 0000000..104b9e6 --- /dev/null +++ b/docs/examples/wireless_lan_group.py @@ -0,0 +1,94 @@ +""" +WirelessLANGroup entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting WirelessLANGroup entities: +- wireless_lan_group_minimal: Required fields only +- wireless_lan_group_extended: Common optional fields +- wireless_lan_group_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Entity, + Owner, + OwnerGroup, + Tag, + WirelessLANGroup, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "wireless_lan_group-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a WirelessLANGroup entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + wireless_lan_group = wireless_lan_group_minimal() + # wireless_lan_group = wireless_lan_group_extended() + # wireless_lan_group = wireless_lan_group_explicit() + + response = client.ingest( + entities=[Entity(wireless_lan_group=wireless_lan_group)] + ) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("WirelessLANGroup ingested successfully") + + +def wireless_lan_group_minimal() -> WirelessLANGroup: + """Create a WirelessLANGroup with only required fields using flat strings.""" + return WirelessLANGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ) + + +def wireless_lan_group_extended() -> WirelessLANGroup: + """Create a WirelessLANGroup with common optional fields.""" + return WirelessLANGroup( + name="Example Name", + slug="example-slug", + metadata={"source": "example", "custom_key": "custom_value"}, + description="Example description", + comments="Example comments", + ) + + +def wireless_lan_group_explicit() -> WirelessLANGroup: + """Create a WirelessLANGroup with fully nested objects and all common fields.""" + return WirelessLANGroup( + name="Example Name", + slug="example-slug", + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + description="Example description", + comments="Example comments", + parent=WirelessLANGroup( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/docs/examples/wireless_link.py b/docs/examples/wireless_link.py new file mode 100644 index 0000000..a22335e --- /dev/null +++ b/docs/examples/wireless_link.py @@ -0,0 +1,174 @@ +""" +WirelessLink entity examples for the Diode Python SDK. + +This module demonstrates three patterns for ingesting WirelessLink entities: +- wireless_link_minimal: Required fields only +- wireless_link_extended: Common optional fields +- wireless_link_explicit: Fully nested objects with all fields +""" + +from netboxlabs.diode.sdk import DiodeClient +from netboxlabs.diode.sdk.ingester import ( + Device, + DeviceRole, + DeviceType, + Entity, + Interface, + Manufacturer, + Owner, + OwnerGroup, + Site, + Tag, + Tenant, + WirelessLink, +) + +TARGET = "grpc://localhost:8080/diode" +APP_NAME = "wireless_link-example" +APP_VERSION = "1.0.0" +CLIENT_ID = "diode" +CLIENT_SECRET = "changeme" + + +def main(): + """Main execution - demonstrates ingesting a WirelessLink entity.""" + with DiodeClient( + target=TARGET, + app_name=APP_NAME, + app_version=APP_VERSION, + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + ) as client: + # Choose one of the three patterns: + wireless_link = wireless_link_minimal() + # wireless_link = wireless_link_extended() + # wireless_link = wireless_link_explicit() + + response = client.ingest(entities=[Entity(wireless_link=wireless_link)]) + if response.errors: + print(f"Errors: {response.errors}") + else: + print("WirelessLink ingested successfully") + + +def wireless_link_minimal() -> WirelessLink: + """Create a WirelessLink with only required fields using flat strings.""" + return WirelessLink( + interface_a="Example Interface A", # flat string -> Interface + interface_b="Example Interface B", # flat string -> Interface + metadata={"source": "example"}, + ) + + +def wireless_link_extended() -> WirelessLink: + """Create a WirelessLink with common optional fields.""" + return WirelessLink( + interface_a="Example Interface A", + interface_b="Example Interface B", + metadata={"source": "example", "custom_key": "custom_value"}, + status="connected", + description="Example description", + ssid="ExampleSSID", + tenant="Example Tenant", + auth_type="open", + auth_cipher="aes", + auth_psk="Example Auth Psk", + distance=1.0, + distance_unit="ft", + comments="Example comments", + ) + + +def wireless_link_explicit() -> WirelessLink: + """Create a WirelessLink with fully nested objects and all common fields.""" + return WirelessLink( + interface_a=Interface( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="Example Type", + metadata={"source": "example"}, + ), + interface_b=Interface( + device=Device( + device_type=DeviceType( + manufacturer=Manufacturer( + name="Example Name", + slug="example-slug", + metadata={"source": "example"}, + ), + model="Model X", + slug="example-slug", + metadata={"source": "example"}, + ), + role=DeviceRole( + name="Example Name", + slug="example-slug", + color="0000ff", + metadata={"source": "example"}, + ), + site=Site( + name="Example Name", + slug="example-slug", + status="active", + metadata={"source": "example"}, + ), + status="active", + metadata={"source": "example"}, + ), + name="Example Name", + type="Example Type", + metadata={"source": "example"}, + ), + metadata={ + "source": "example", + "custom_key": "custom_value", + "collected_at": "2024-01-15T10:30:00Z", + }, + status="connected", + description="Example description", + comments="Example comments", + ssid="ExampleSSID", + auth_type="open", + auth_cipher="aes", + auth_psk="Example Auth Psk", + distance=1.0, + distance_unit="ft", + tenant=Tenant( + name="Example Name", slug="example-slug", metadata={"source": "example"} + ), + owner=Owner( + name="Example Name", + group=OwnerGroup(name="Example Name", metadata={"source": "example"}), + metadata={"source": "example"}, + ), + tags=[Tag(name="production")], + ) + + +if __name__ == "__main__": + main() diff --git a/netboxlabs/diode/sdk/ingester.py b/netboxlabs/diode/sdk/ingester.py index 2ff6094..9a57429 100644 --- a/netboxlabs/diode/sdk/ingester.py +++ b/netboxlabs/diode/sdk/ingester.py @@ -2,7 +2,8 @@ # # Generated code. DO NOT EDIT. -# Timestamp: 2026-02-02 16:58:59Z +# Source: NetBox v4.5.0 +# Timestamp: 2026-02-17 23:39:36Z # # ruff: noqa: C901