From 82625165184a6fcf9ec45c4fa93407f5308792e5 Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 7 May 2025 10:00:53 -0700 Subject: [PATCH 1/4] Add constants and new APIs --- constants.py | 2397 ++++++++++++++++++++++++++++++++++++++++++++++++++ server.py | 257 +++--- 2 files changed, 2542 insertions(+), 112 deletions(-) create mode 100644 constants.py diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..aaf04a0 --- /dev/null +++ b/constants.py @@ -0,0 +1,2397 @@ + +API_ENDPOINTS = { + # DCIM + "cables": { + "endpoint": "dcim/cables", + "filters": [ + {"name": "type", "description": "Type of cable"}, + {"name": "status", "description": "Operational status of the cable"}, + {"name": "tenant", "description": "Tenant associated with the cable"}, + {"name": "site", "description": "Site where the cable is located"}, + {"name": "rack", "description": "Rack where the cable is terminated"}, + {"name": "device", "description": "Device connected by the cable"}, + {"name": "interface", "description": "Interface connected by the cable"}, + {"name": "length", "description": "Length of the cable"}, + { + "name": "length_unit", + "description": "Unit of measurement for cable length", + }, + {"name": "color", "description": "Color of the cable"}, + {"name": "label", "description": "Label assigned to the cable"}, + {"name": "description", "description": "Description of the cable"}, + {"name": "tag", "description": "Tag associated with the cable"}, + ], + "description": "Manage physical cable connections between devices.", + "fields": [ + "id", + "url", + "display", + "termination_a_type", + "termination_a_id", + "termination_a", + "termination_b_type", + "termination_b_id", + "termination_b", + "type", + "status", + "tenant", + "label", + "color", + "length", + "length_unit", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated", + "_occupied" + ], + }, + "console-ports": { + "endpoint": "dcim/console-ports", + "filters": [ + {"name": "name", "description": "Name of the console port"}, + { + "name": "device", + "description": "Device to which the console port belongs", + }, + {"name": "label", "description": "Label assigned to the console port"}, + {"name": "description", "description": "Description of the console port"}, + {"name": "speed", "description": "Speed of the console port"}, + {"name": "tag", "description": "Tag associated with the console port"}, + ], + "description": "Manage console ports on devices.", + "fields": [ + "id", + "url", + "display", + "device", + "module", + "name", + "label", + "type", + "speed", + "description", + "mark_connected", + "cable", + "cable_peer", + "cable_peer_type", + "connected_endpoint", + "connected_endpoint_type", + "connected_endpoint_reachable", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "console-server-ports": { + "endpoint": "dcim/console-server-ports", + "filters": [ + {"name": "name", "description": "Name of the console server port"}, + { + "name": "device", + "description": "Device to which the console server port belongs", + }, + { + "name": "label", + "description": "Label assigned to the console server port", + }, + { + "name": "description", + "description": "Description of the console server port", + }, + {"name": "speed", "description": "Speed of the console server port"}, + { + "name": "tag", + "description": "Tag associated with the console server port", + }, + ], + "description": "Manage console server ports on devices.", + "fields": [ + "id", + "url", + "display", + "device", + "module", + "name", + "label", + "type", + "speed", + "description", + "mark_connected", + "cable", + "cable_peer", + "cable_peer_type", + "connected_endpoint", + "connected_endpoint_type", + "connected_endpoint_reachable", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "devices": { + "endpoint": "dcim/devices", + "filters": [ + {"name": "name", "description": "Exact match on device name"}, + { + "name": "name__ic", + "description": "Case-insensitive substring match on device name", + }, + {"name": "serial", "description": "Serial number of the device"}, + {"name": "asset_tag", "description": "Asset tag of the device"}, + {"name": "device_type_id", "description": "Filter by DeviceType ID"}, + {"name": "device_type", "description": "Filter by DeviceType name"}, + {"name": "device_role_id", "description": "Filter by DeviceRole ID"}, + {"name": "device_role", "description": "Filter by DeviceRole slug"}, + {"name": "platform_id", "description": "Filter by Platform ID"}, + {"name": "platform", "description": "Filter by Platform slug"}, + {"name": "status", "description": "Operational status of the device"}, + {"name": "region_id", "description": "Filter by Region ID"}, + {"name": "region", "description": "Filter by Region slug"}, + {"name": "site_group_id", "description": "Filter by SiteGroup ID"}, + {"name": "site_group", "description": "Filter by SiteGroup slug"}, + {"name": "site_id", "description": "Filter by Site ID"}, + {"name": "site", "description": "Filter by Site slug"}, + {"name": "location_id", "description": "Filter by Location ID"}, + {"name": "location", "description": "Filter by Location slug"}, + {"name": "rack_id", "description": "Filter by Rack ID"}, + {"name": "rack", "description": "Filter by Rack name"}, + {"name": "cluster_id", "description": "Filter by Cluster ID"}, + {"name": "cluster", "description": "Filter by Cluster name"}, + {"name": "tenant_id", "description": "Filter by Tenant ID"}, + {"name": "tenant", "description": "Filter by Tenant slug"}, + {"name": "mac_address", "description": "Filter by MAC address"}, + { + "name": "has_primary_ip", + "description": "Filter devices with a primary IP", + }, + { + "name": "virtual_chassis_id", + "description": "Filter by Virtual Chassis ID", + }, + { + "name": "is_virtual_chassis_member", + "description": "Filter devices that are members of a virtual chassis", + }, + {"name": "tag", "description": "Filter by tag"}, + ], + "description": "Manage devices such as routers, switches, servers, and more.", + "fields": [ + "id", + "url", + "display", + "name", + "device_type", + "device_role", + "tenant", + "platform", + "serial", + "asset_tag", + "site", + "location", + "rack", + "position", + "face", + "parent_device", + "status", + "airflow", + "primary_ip4", + "primary_ip6", + "cluster", + "virtual_chassis", + "vc_position", + "vc_priority", + "description", + "config_template", + "comments", + "local_context_data", + "tags", + "custom_fields", + "created", + "last_updated", + "secrets_group", + "config_context", + "count_ipaddresses", + "count_fhrp_groups", + "console_port_count", + "console_server_port_count", + "power_port_count", + "power_outlet_count", + "interface_count", + "front_port_count", + "rear_port_count", + "device_bay_count", + "module_bay_count" + ], + }, + "device-bays": { + "endpoint": "dcim/device-bays", + "filters": [ + {"name": "name", "description": "Name of the device bay"}, + { + "name": "device_id", + "description": "ID of the device to which the bay belongs", + }, + { + "name": "device", + "description": "Name of the device to which the bay belongs", + }, + {"name": "label", "description": "Label assigned to the device bay"}, + {"name": "description", "description": "Description of the device bay"}, + {"name": "tag", "description": "Tag associated with the device bay"}, + ], + "description": "Manage bays within devices for installing modules or child devices.", + "fields": [ + "id", + "url", + "display", + "device", + "name", + "label", + "description", + "installed_device", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "device-roles": { + "endpoint": "dcim/device-roles", + "filters": [ + {"name": "name", "description": "Name of the device role"}, + {"name": "slug", "description": "Slug of the device role"}, + {"name": "color", "description": "Color associated with the device role"}, + { + "name": "vm_role", + "description": "Boolean indicating if the role is for virtual machines", + }, + {"name": "tag", "description": "Tag associated with the device role"}, + ], + "description": "Define roles for devices to categorize their function.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "color", + "vm_role", + "description", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "device-types": { + "endpoint": "dcim/device-types", + "filters": [ + {"name": "model", "description": "Exact model name of the device type"}, + {"name": "slug", "description": "Slugified version of the model name"}, + { + "name": "manufacturer", + "description": "Slug of the associated manufacturer", + }, + { + "name": "manufacturer_id", + "description": "ID of the associated manufacturer", + }, + {"name": "part_number", "description": "Manufacturer part number"}, + {"name": "u_height", "description": "Height of the device in rack units"}, + { + "name": "is_full_depth", + "description": "Boolean indicating if the device is full depth", + }, + { + "name": "subdevice_role", + "description": "Role of the device type (parent/child)", + }, + {"name": "airflow", "description": "Airflow direction for the device"}, + {"name": "tag", "description": "Tag assigned to the device type"}, + ], + "description": "Manage device hardware models from manufacturers (e.g., model + dimensions).", + "fields": [ + "id", + "url", + "display", + "manufacturer", + "model", + "slug", + "part_number", + "u_height", + "is_full_depth", + "subdevice_role", + "airflow", + "weight", + "weight_unit", + "front_image", + "rear_image", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "front-ports": { + "endpoint": "dcim/front-ports", + "filters": [ + {"name": "name", "description": "Name of the front port"}, + {"name": "device", "description": "Device to which the front port belongs"}, + {"name": "type", "description": "Type of the front port"}, + {"name": "rear_port", "description": "Associated rear port"}, + {"name": "rear_port_position", "description": "Position on the rear port"}, + {"name": "label", "description": "Label assigned to the front port"}, + {"name": "description", "description": "Description of the front port"}, + {"name": "tag", "description": "Tag associated with the front port"}, + ], + "description": "Manage front ports on devices.", + "fields": [ + "id", + "url", + "display", + "device", + "module", + "name", + "label", + "type", + "color", + "rear_port", + "rear_port_position", + "description", + "mark_connected", + "cable", + "cable_peer", + "cable_peer_type", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "interfaces": { + "endpoint": "dcim/interfaces", + "filters": [ + {"name": "name", "description": "Name of the interface"}, + {"name": "device", "description": "Device to which the interface belongs"}, + {"name": "type", "description": "Type of the interface"}, + {"name": "enabled", "description": "Operational status of the interface"}, + {"name": "mac_address", "description": "MAC address of the interface"}, + {"name": "mtu", "description": "MTU size of the interface"}, + {"name": "mgmt_only", "description": "Management-only status"}, + { + "name": "mode", + "description": "Mode of the interface (e.g., access, tagged)", + }, + { + "name": "tagged_vlans", + "description": "Tagged VLANs associated with the interface", + }, + { + "name": "untagged_vlan", + "description": "Untagged VLAN associated with the interface", + }, + {"name": "label", "description": "Label assigned to the interface"}, + {"name": "description", "description": "Description of the interface"}, + {"name": "tag", "description": "Tag associated with the interface"}, + ], + "description": "Manage network interfaces on devices.", + "fields": [ + "id", + "url", + "display", + "device", + "vdcs", + "module", + "name", + "label", + "type", + "enabled", + "parent", + "bridge", + "lag", + "mtu", + "mac_address", + "speed", + "duplex", + "wwn", + "mgmt_only", + "description", + "mode", + "rf_role", + "rf_channel", + "rf_channel_frequency", + "rf_channel_width", + "tx_power", + "untagged_vlan", + "tagged_vlans", + "mark_connected", + "cable", + "cable_peer", + "cable_peer_type", + "connected_endpoint", + "connected_endpoint_type", + "connected_endpoint_reachable", + "wireless_link", + "wireless_lans", + "vrf", + "l2vpn_termination", + "count_ipaddresses", + "count_fhrp_groups", + "tags", + "custom_fields", + "created", + "last_updated", + "occupied" + ], + }, + "inventory-items": { + "endpoint": "dcim/inventory-items", + "filters": [ + {"name": "name", "description": "Name of the inventory item"}, + { + "name": "device", + "description": "Device to which the inventory item belongs", + }, + {"name": "parent", "description": "Parent inventory item"}, + { + "name": "manufacturer", + "description": "Manufacturer of the inventory item", + }, + {"name": "part_id", "description": "Part ID of the inventory item"}, + {"name": "serial", "description": "Serial number of the inventory item"}, + {"name": "asset_tag", "description": "Asset tag of the inventory item"}, + { + "name": "discovered", + "description": "Discovery status of the inventory item", + }, + {"name": "label", "description": "Label assigned to the inventory item"}, + {"name": "description", "description": "Description of the inventory item"}, + {"name": "tag", "description": "Tag associated with the inventory item"}, + ], + "description": "Manage inventory items within devices.", + "fields": [ + "id", + "url", + "display", + "device", + "parent", + "name", + "label", + "role", + "manufacturer", + "part_id", + "serial", + "asset_tag", + "discovered", + "description", + "component_type", + "component_id", + "component", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "locations": { + "endpoint": "dcim/locations", + "filters": [ + {"name": "name", "description": "Name of the location"}, + {"name": "site", "description": "Site to which the location belongs"}, + {"name": "parent", "description": "Parent location"}, + {"name": "status", "description": "Operational status of the location"}, + {"name": "description", "description": "Description of the location"}, + {"name": "tag", "description": "Tag associated with the location"}, + ], + "description": "Manage specific areas within sites.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "site", + "parent", + "status", + "tenant", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "rack_count", + "device_count", + "depth" + ], + }, + "manufacturers": { + "endpoint": "dcim/manufacturers", + "filters": [ + {"name": "name", "description": "Name of the manufacturer"}, + {"name": "slug", "description": "Slug of the manufacturer"}, + {"name": "description", "description": "Description of the manufacturer"}, + {"name": "tag", "description": "Tag associated with the manufacturer"}, + ], + "description": "Manage manufacturers of devices and components.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "description", + "devicetype_count", + "inventoryitemtype_count", + "moduletype_count", + "platform_count", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "modules": { + "endpoint": "dcim/modules", + "filters": [ + {"name": "name", "description": "Name of the module"}, + { + "name": "device", + "description": "Device in which the module is installed", + }, + {"name": "module_type", "description": "Type of the module"}, + {"name": "status", "description": "Operational status of the module"}, + {"name": "serial", "description": "Serial number of the module"}, + {"name": "asset_tag", "description": "Asset tag of the module"}, + {"name": "label", "description": "Label assigned to the module"}, + {"name": "description", "description": "Description of the module"}, + {"name": "tag", "description": "Tag associated with the module"}, + ], + "description": "Manage modules installed within devices.", + "fields": [ + "id", + "url", + "display", + "device", + "module_bay", + "module_type", + "status", + "serial", + "asset_tag", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "module-bays": { + "endpoint": "dcim/module-bays", + "filters": [ + {"name": "name", "description": "Name of the module bay"}, + {"name": "device", "description": "Device to which the module bay belongs"}, + {"name": "label", "description": "Label assigned to the module bay"}, + {"name": "description", "description": "Description of the module bay"}, + {"name": "tag", "description": "Tag associated with the module bay"}, + ], + "description": "Manage module bays within devices.", + "fields": [ + "id", + "url", + "display", + "device", + "name", + "label", + "position", + "description", + "installed_module_id", + "installed_module", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "module-types": { + "endpoint": "dcim/module-types", + "filters": [ + {"name": "manufacturer", "description": "Manufacturer of the module type"}, + {"name": "model", "description": "Model name of the module type"}, + {"name": "part_number", "description": "Part number of the module type"}, + {"name": "description", "description": "Description of the module type"}, + {"name": "tag", "description": "Tag associated with the module type"}, + ], + "description": "Manage types of modules that can be installed in devices.", + "fields": [ + "id", + "url", + "display", + "manufacturer", + "model", + "part_number", + "weight", + "weight_unit", + "description", + "comments", + "front_image", + "rear_image", + "component_data", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "platforms": { + "endpoint": "dcim/platforms", + "filters": [ + {"name": "name", "description": "Name of the platform (e.g., IOS, JunOS)"}, + {"name": "slug", "description": "Slugified version of the platform name"}, + { + "name": "manufacturer", + "description": "Manufacturer associated with the platform", + }, + { + "name": "napalm_driver", + "description": "NAPALM driver used for the platform", + }, + { + "name": "napalm_args", + "description": "Additional arguments passed to NAPALM driver", + }, + { + "name": "description", + "description": "Optional description of the platform", + }, + {"name": "tag", "description": "Tag assigned to the platform"}, + ], + "description": "Manage software platforms (e.g., operating systems or firmware) used on devices.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "manufacturer", + "config_template", + "napalm_driver", + "napalm_args", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "device_count", + "virtualmachine_count" + ], + }, + "power-feeds": { + "endpoint": "dcim/power-feeds", + "filters": [ + {"name": "name", "description": "Name of the power feed"}, + {"name": "site", "description": "Site where the power feed is located"}, + { + "name": "power_panel", + "description": "Power panel to which the feed is connected", + }, + {"name": "rack", "description": "Rack served by the power feed"}, + {"name": "status", "description": "Operational status of the power feed"}, + { + "name": "type", + "description": "Type of power feed (e.g., primary, redundant)", + }, + {"name": "supply", "description": "Supply type (e.g., AC, DC)"}, + { + "name": "phase", + "description": "Phase type (e.g., single-phase, three-phase)", + }, + {"name": "voltage", "description": "Voltage of the power feed"}, + {"name": "amperage", "description": "Amperage of the power feed"}, + { + "name": "max_utilization", + "description": "Maximum utilization percentage", + }, + {"name": "available_power", "description": "Available power capacity"}, + {"name": "description", "description": "Description of the power feed"}, + {"name": "tag", "description": "Tag associated with the power feed"}, + ], + "description": "Manage power feeds supplying racks and devices.", + "fields": [ + "id", + "url", + "display", + "power_panel", + "rack", + "name", + "status", + "type", + "supply", + "phase", + "voltage", + "amperage", + "max_utilization", + "available_power", + "description", + "comments", + "mark_connected", + "cable", + "cable_peer", + "cable_peer_type", + "connected_endpoint", + "connected_endpoint_type", + "connected_endpoint_reachable", + "_occupied", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "power-outlets": { + "endpoint": "dcim/power-outlets", + "filters": [ + {"name": "name", "description": "Name of the power outlet"}, + { + "name": "device", + "description": "Device to which the power outlet belongs", + }, + {"name": "type", "description": "Type of power outlet"}, + {"name": "power_port", "description": "Associated power port"}, + {"name": "feed_leg", "description": "Feed leg designation"}, + {"name": "label", "description": "Label assigned to the power outlet"}, + {"name": "description", "description": "Description of the power outlet"}, + {"name": "tag", "description": "Tag associated with the power outlet"}, + ], + "description": "Manage power outlets on devices.", + "fields": [ + "id", + "url", + "display", + "device", + "module", + "name", + "label", + "type", + "power_port", + "feed_leg", + "description", + "mark_connected", + "cable", + "cable_peer", + "cable_peer_type", + "connected_endpoint", + "connected_endpoint_type", + "connected_endpoint_reachable", + "_occupied", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "power-panels": { + "endpoint": "dcim/power-panels", + "filters": [ + {"name": "name", "description": "Name of the power panel"}, + {"name": "site", "description": "Site where the power panel is located"}, + {"name": "location", "description": "Location within the site"}, + {"name": "description", "description": "Description of the power panel"}, + {"name": "tag", "description": "Tag associated with the power panel"}, + ], + "description": "Manage power distribution panels within sites.", + "fields": [ + "id", + "url", + "display", + "site", + "location", + "name", + "description", + "comments", + "rack_group", + "powerfeed_count", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "power-ports": { + "endpoint": "dcim/power-ports", + "filters": [ + {"name": "name", "description": "Name of the power port"}, + {"name": "device", "description": "Device to which the power port belongs"}, + {"name": "type", "description": "Type of power port"}, + {"name": "maximum_draw", "description": "Maximum power draw"}, + {"name": "allocated_draw", "description": "Allocated power draw"}, + {"name": "label", "description": "Label assigned to the power port"}, + {"name": "description", "description": "Description of the power port"}, + {"name": "tag", "description": "Tag associated with the power port"}, + ], + "description": "Manage power input ports on devices.", + "fields": [ + "id", + "url", + "display", + "device", + "module", + "name", + "label", + "type", + "maximum_draw", + "allocated_draw", + "description", + "mark_connected", + "cable", + "cable_peer", + "cable_peer_type", + "connected_endpoint", + "connected_endpoint_type", + "connected_endpoint_reachable", + "_occupied", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "racks": { + "endpoint": "dcim/racks", + "filters": [ + {"name": "name", "description": "Name of the rack"}, + {"name": "facility_id", "description": "Facility ID of the rack"}, + {"name": "site", "description": "Site where the rack is located"}, + {"name": "location", "description": "Location within the site"}, + {"name": "status", "description": "Operational status of the rack"}, + {"name": "tenant", "description": "Tenant assigned to the rack"}, + {"name": "role", "description": "Role assigned to the rack"}, + {"name": "serial", "description": "Serial number of the rack"}, + {"name": "asset_tag", "description": "Asset tag of the rack"}, + {"name": "type", "description": "Type of rack (e.g., 2-post, 4-post)"}, + {"name": "width", "description": "Width of the rack"}, + {"name": "u_height", "description": "Height of the rack in rack units"}, + {"name": "desc_units", "description": "Descending units flag"}, + {"name": "outer_width", "description": "Outer width of the rack"}, + {"name": "outer_depth", "description": "Outer depth of the rack"}, + { + "name": "outer_unit", + "description": "Unit of measurement for outer dimensions", + }, + {"name": "mounting_depth", "description": "Mounting depth of the rack"}, + {"name": "weight", "description": "Weight of the rack"}, + {"name": "max_weight", "description": "Maximum weight capacity"}, + {"name": "weight_unit", "description": "Unit of measurement for weight"}, + {"name": "description", "description": "Description of the rack"}, + {"name": "tag", "description": "Tag associated with the rack"}, + ], + "description": "Manage racks housing devices.", + "fields": [ + "id", + "url", + "display", + "name", + "facility_id", + "site", + "location", + "tenant", + "status", + "role", + "serial", + "asset_tag", + "type", + "width", + "u_height", + "desc_units", + "outer_width", + "outer_depth", + "outer_unit", + "mounting_depth", + "weight", + "max_weight", + "weight_unit", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated", + "device_count", + "powerfeed_count" + ], + }, + "rack-reservations": { + "endpoint": "dcim/rack-reservations", + "filters": [ + {"name": "site", "description": "Site where the rack reservation is made"}, + {"name": "location", "description": "Location within the site"}, + {"name": "rack", "description": "Rack being reserved"}, + {"name": "units", "description": "Specific rack units being reserved"}, + {"name": "user", "description": "User who made the reservation"}, + {"name": "tenant", "description": "Tenant associated with the reservation"}, + {"name": "description", "description": "Description of the reservation"}, + {"name": "tag", "description": "Tag associated with the rack reservation"}, + ], + "description": "Manage reservations for rack units.", + "fields": [ + "id", + "url", + "display", + "rack", + "units", + "user", + "tenant", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "rack-roles": { + "endpoint": "dcim/rack-roles", + "filters": [ + {"name": "name", "description": "Name of the rack role"}, + {"name": "slug", "description": "Slug of the rack role"}, + {"name": "color", "description": "Color associated with the rack role"}, + {"name": "description", "description": "Description of the rack role"}, + {"name": "tag", "description": "Tag associated with the rack role"}, + ], + "description": "Define roles to categorize racks by their function.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "color", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "rack_count" + ], + }, + "regions": { + "endpoint": "dcim/regions", + "filters": [ + {"name": "name", "description": "Name of the region"}, + {"name": "slug", "description": "Slug of the region"}, + {"name": "parent", "description": "Parent region"}, + {"name": "description", "description": "Description of the region"}, + {"name": "tag", "description": "Tag associated with the region"}, + ], + "description": "Organize sites by geographic region.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "parent", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "_depth", + "site_count" + ], + }, + "sites": { + "endpoint": "dcim/sites", + "filters": [ + {"name": "name", "description": "Name of the site"}, + {"name": "slug", "description": "Slug of the site"}, + {"name": "status", "description": "Operational status of the site"}, + {"name": "region", "description": "Region to which the site belongs"}, + {"name": "group", "description": "Group to which the site belongs"}, + {"name": "tenant", "description": "Tenant assigned to the site"}, + { + "name": "asn", + "description": "Autonomous System Number (ASN) of the site", + }, + {"name": "latitude", "description": "Latitude coordinate of the site"}, + {"name": "longitude", "description": "Longitude coordinate of the site"}, + {"name": "description", "description": "Description of the site"}, + {"name": "tag", "description": "Tag associated with the site"}, + ], + "description": "Manage physical locations where infrastructure is deployed.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "status", + "region", + "group", + "tenant", + "facility", + "time_zone", + "physical_address", + "shipping_address", + "latitude", + "longitude", + "description", + "comments", + "asns", + "tags", + "custom_fields", + "created", + "last_updated", + "circuit_count", + "device_count", + "prefix_count", + "rack_count", + "virtualmachine_count", + "vlan_count" + ], + }, + "site-groups": { + "endpoint": "dcim/site-groups", + "filters": [ + {"name": "name", "description": "Name of the site group"}, + {"name": "slug", "description": "Slug of the site group"}, + {"name": "parent", "description": "Parent site group"}, + {"name": "description", "description": "Description of the site group"}, + {"name": "tag", "description": "Tag associated with the site group"}, + ], + "description": "Classify sites by role or function.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "parent", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "_depth", + "site_count" + ], + }, + "virtual-chassis": { + "endpoint": "dcim/virtual-chassis", + "filters": [ + {"name": "domain", "description": "Domain of the virtual chassis"}, + {"name": "master", "description": "Master device of the virtual chassis"}, + {"name": "member", "description": "Member devices of the virtual chassis"}, + {"name": "tag", "description": "Tag associated with the virtual chassis"}, + ], + "description": "Manage virtual chassis configurations comprising multiple devices.", + "fields": [ + "id", + "url", + "display", + "name", + "domain", + "master", + "members", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + + + # IPAM + "asns": { + "endpoint": "ipam/asns", + "filters": [ + {"name": "asn", "description": "Filter by ASN number"}, + { + "name": "rir", + "description": "Filter by associated Regional Internet Registry (RIR)", + }, + {"name": "site", "description": "Filter by assigned site"}, + {"name": "tenant", "description": "Filter by assigned tenant"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage Autonomous System Numbers (ASNs) used in the network.", + "fields": [ + "id", + "url", + "display", + "asn", + "rir", + "tenant", + "site", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "asn-ranges": { + "endpoint": "ipam/asn-ranges", + "filters": [ + {"name": "start_asn", "description": "Filter by starting ASN in the range"}, + {"name": "end_asn", "description": "Filter by ending ASN in the range"}, + {"name": "rir", "description": "Filter by associated RIR"}, + {"name": "tenant", "description": "Filter by assigned tenant"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage ranges of ASNs allocated by RIRs.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "rir", + "start_asn", + "end_asn", + "tenant", + "description", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "aggregates": { + "endpoint": "ipam/aggregates", + "filters": [ + {"name": "prefix", "description": "Filter by aggregate prefix"}, + {"name": "rir", "description": "Filter by associated RIR"}, + {"name": "date_added", "description": "Filter by date added"}, + {"name": "description", "description": "Filter by description"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage top-level IP address allocations from RIRs.", + "fields": [ + "id", + "url", + "display", + "family", + "prefix", + "rir", + "tenant", + "date_added", + "description", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "fhrp-groups": { + "endpoint": "ipam/fhrp-groups", + "filters": [ + { + "name": "protocol", + "description": "Filter by FHRP protocol (e.g., HSRP, VRRP)", + }, + {"name": "group_id", "description": "Filter by group ID"}, + {"name": "auth_type", "description": "Filter by authentication type"}, + {"name": "description", "description": "Filter by description"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage First Hop Redundancy Protocol (FHRP) groups.", + "fields": [ + "id", + "url", + "display", + "protocol", + "group_id", + "auth_type", + "auth_key", + "description", + "ip_addresses", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "ip-addresses": { + "endpoint": "ipam/ip-addresses", + "filters": [ + {"name": "address", "description": "Filter by IP address"}, + { + "name": "family", + "description": "Filter by address family (IPv4 or IPv6)", + }, + {"name": "status", "description": "Filter by operational status"}, + { + "name": "role", + "description": "Filter by role (e.g., loopback, secondary)", + }, + { + "name": "assigned_object_type", + "description": "Filter by assigned object type", + }, + { + "name": "assigned_object_id", + "description": "Filter by assigned object ID", + }, + {"name": "dns_name", "description": "Filter by DNS name"}, + {"name": "vrf", "description": "Filter by VRF"}, + {"name": "tenant", "description": "Filter by assigned tenant"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage individual IP addresses and their assignments.", + "fields": [ + "id", + "url", + "display", + "family", + "address", + "vrf", + "tenant", + "status", + "role", + "assigned_object_type", + "assigned_object_id", + "assigned_object", + "nat_inside", + "nat_outside", + "dns_name", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "ip-ranges": { + "endpoint": "ipam/ip-ranges", + "filters": [ + { + "name": "start_address", + "description": "Filter by starting IP address of the range", + }, + { + "name": "end_address", + "description": "Filter by ending IP address of the range", + }, + {"name": "size", "description": "Filter by size of the range"}, + {"name": "status", "description": "Filter by operational status"}, + {"name": "role", "description": "Filter by role"}, + {"name": "vrf", "description": "Filter by VRF"}, + {"name": "tenant", "description": "Filter by assigned tenant"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage ranges of consecutive IP addresses.", + "fields": [ + "id", + "url", + "display", + "start_address", + "end_address", + "size", + "vrf", + "tenant", + "status", + "role", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "prefixes": { + "endpoint": "ipam/prefixes", + "filters": [ + {"name": "prefix", "description": "Filter by prefix"}, + {"name": "within", "description": "Filter prefixes within a parent prefix"}, + { + "name": "within_include", + "description": "Include parent prefix in results", + }, + { + "name": "family", + "description": "Filter by address family (IPv4 or IPv6)", + }, + {"name": "status", "description": "Filter by operational status"}, + {"name": "role", "description": "Filter by role"}, + {"name": "is_pool", "description": "Filter by whether prefix is a pool"}, + {"name": "vrf", "description": "Filter by VRF"}, + {"name": "tenant", "description": "Filter by assigned tenant"}, + {"name": "site", "description": "Filter by assigned site"}, + {"name": "vlan_vid", "description": "Filter by VLAN ID"}, + {"name": "mask_length", "description": "Filter by mask length"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage IP prefixes and their hierarchical relationships.", + "fields": [ + "id", + "url", + "display", + "family", + "prefix", + "site", + "vrf", + "tenant", + "vlan", + "status", + "role", + "is_pool", + "mark_utilized", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "rirs": { + "endpoint": "ipam/rirs", + "filters": [ + {"name": "name", "description": "Filter by RIR name"}, + { + "name": "is_private", + "description": "Filter by whether RIR is designated for private use", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage Regional Internet Registries (RIRs) responsible for IP address allocations.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "is_private", + "description", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "roles": { + "endpoint": "ipam/roles", + "filters": [ + {"name": "name", "description": "Filter by role name"}, + {"name": "slug", "description": "Filter by role slug"}, + {"name": "weight", "description": "Filter by role weight"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Define functional roles for prefixes and VLANs.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "weight", + "description", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "route-targets": { + "endpoint": "ipam/route-targets", + "filters": [ + { + "name": "name", + "description": "Exact name of the route target (e.g., 65000:100)", + }, + { + "name": "importing_vrfs", + "description": "ID of a VRF that imports this route target", + }, + { + "name": "exporting_vrfs", + "description": "ID of a VRF that exports this route target", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage BGP Route Targets for import/export policies in VRFs.", + "fields": [ + "id", + "url", + "display", + "name", + "tenant", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "services": { + "endpoint": "ipam/services", + "filters": [ + {"name": "name", "description": "Name of the service (e.g., HTTP, SSH)"}, + {"name": "protocol", "description": "Transport protocol (TCP or UDP)"}, + {"name": "ports", "description": "Port number used by the service"}, + { + "name": "device_id", + "description": "ID of the device hosting the service", + }, + { + "name": "virtual_machine_id", + "description": "ID of the VM hosting the service", + }, + {"name": "ipaddresses", "description": "Associated IP addresses"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage services running on devices or virtual machines, typically defined by port and protocol.", + "fields": [ + "id", + "url", + "display", + "device", + "virtual_machine", + "name", + "ports", + "protocol", + "ipaddresses", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "vlans": { + "endpoint": "ipam/vlans", + "filters": [ + {"name": "vid", "description": "VLAN ID (1–4094)"}, + {"name": "name", "description": "Name of the VLAN"}, + {"name": "status", "description": "Operational status of the VLAN"}, + {"name": "role", "description": "Role assigned to the VLAN"}, + {"name": "site", "description": "Site to which the VLAN belongs"}, + {"name": "group", "description": "VLAN group to which the VLAN belongs"}, + {"name": "tenant", "description": "Tenant associated with the VLAN"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage VLANs, including tagging and site/tenant assignments.", + "fields": [ + "id", + "url", + "display", + "site", + "group", + "vid", + "name", + "tenant", + "status", + "role", + "description", + "comments", + "l2vpn_termination", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "vlan-groups": { + "endpoint": "ipam/vlan-groups", + "filters": [ + {"name": "name", "description": "Name of the VLAN group"}, + {"name": "slug", "description": "Slugified identifier for the VLAN group"}, + { + "name": "scope_type", + "description": "Model to which this group is scoped (e.g., site, region)", + }, + {"name": "scope_id", "description": "ID of the scope object"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Group VLANs under common scopes (site, region, etc.).", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "min_vid", + "max_vid", + "scope_type", + "scope_id", + "scope", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "vlan_count" + ], + }, + "vrfs": { + "endpoint": "ipam/vrfs", + "filters": [ + {"name": "name", "description": "Name of the VRF"}, + {"name": "rd", "description": "Route distinguisher (e.g., 65000:1)"}, + { + "name": "enforce_unique", + "description": "Boolean indicating IP uniqueness enforcement", + }, + {"name": "tenant", "description": "Tenant associated with the VRF"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage Virtual Routing and Forwarding (VRF) tables to isolate IP space.", + "fields": [ + "id", + "url", + "display", + "name", + "rd", + "tenant", + "enforce_unique", + "description", + "comments", + "import_targets", + "export_targets", + "tags", + "custom_fields", + "created", + "last_updated", + "ipaddress_count", + "prefix_count" + ], + }, + # Circuits + "circuits": { + "endpoint": "circuits/circuits", + "filters": [ + {"name": "provider", "description": "Filter by provider name or ID"}, + { + "name": "provider_account", + "description": "Filter by provider account ID", + }, + {"name": "cid", "description": "Filter by circuit ID"}, + {"name": "type", "description": "Filter by circuit type name or ID"}, + {"name": "status", "description": "Filter by operational status"}, + {"name": "tenant", "description": "Filter by tenant name or ID"}, + {"name": "site", "description": "Filter by site name or ID"}, + {"name": "commit_rate", "description": "Filter by commit rate (Kbps)"}, + {"name": "installed", "description": "Filter by installation date"}, + {"name": "terminated", "description": "Filter by termination date"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage physical circuits provided by external providers.", + "fields": [ + "id", + "url", + "display", + "cid", + "provider", + "provider_account", + "type", + "status", + "tenant", + "termination_a", + "termination_z", + "install_date", + "termination_date", + "commit_rate", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "circuit-types": { + "endpoint": "circuits/circuit-types", + "filters": [ + {"name": "name", "description": "Filter by circuit type name"}, + {"name": "slug", "description": "Filter by circuit type slug"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Define functional types of circuits (e.g., Internet, MPLS).", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "circuit_count" + ], + }, + "circuit-terminations": { + "endpoint": "circuits/circuit-terminations", + "filters": [ + {"name": "circuit_id", "description": "Filter by circuit ID"}, + {"name": "term_side", "description": "Filter by termination side (A or Z)"}, + {"name": "site", "description": "Filter by site name or ID"}, + { + "name": "provider_network", + "description": "Filter by provider network ID", + }, + {"name": "port_speed", "description": "Filter by port speed (Kbps)"}, + { + "name": "upstream_speed", + "description": "Filter by upstream speed (Kbps)", + }, + {"name": "xconnect_id", "description": "Filter by cross-connect ID"}, + {"name": "pp_info", "description": "Filter by patch panel/port info"}, + {"name": "description", "description": "Filter by description"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage terminations of circuits at sites or provider networks.", + "fields": [ + "id", + "url", + "display", + "circuit", + "term_side", + "site", + "provider_network", + "port_speed", + "upstream_speed", + "xconnect_id", + "pp_info", + "description", + "mark_connected", + "cable", + "cable_peer", + "cable_peer_type", + "link_peer", + "link_peer_type", + "_occupied", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "providers": { + "endpoint": "circuits/providers", + "filters": [ + {"name": "name", "description": "Filter by provider name"}, + {"name": "slug", "description": "Filter by provider slug"}, + {"name": "asn", "description": "Filter by associated ASN"}, + {"name": "account", "description": "Filter by provider account ID"}, + {"name": "portal_url", "description": "Filter by portal URL"}, + {"name": "noc_contact", "description": "Filter by NOC contact information"}, + { + "name": "admin_contact", + "description": "Filter by admin contact information", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage service providers offering circuits.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "asn", + "account", + "portal_url", + "noc_contact", + "admin_contact", + "comments", + "tags", + "custom_fields", + "created", + "last_updated", + "circuit_count" + ], + }, + "provider-networks": { + "endpoint": "circuits/provider-networks", + "filters": [ + {"name": "provider", "description": "Filter by provider name or ID"}, + {"name": "service_id", "description": "Filter by service ID"}, + {"name": "description", "description": "Filter by description"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Represent external provider networks to which circuits can connect.", + "fields": [ + "id", + "url", + "display", + "provider", + "name", + "service_id", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated", + "circuit_termination_count" + ], + }, + # Virtualization + "clusters": { + "endpoint": "virtualization/clusters", + "filters": [ + {"name": "name", "description": "Filter by cluster name"}, + {"name": "type", "description": "Filter by cluster type (name or ID)"}, + {"name": "group", "description": "Filter by cluster group (name or ID)"}, + {"name": "status", "description": "Filter by operational status"}, + {"name": "tenant", "description": "Filter by tenant (name or ID)"}, + {"name": "site", "description": "Filter by assigned site (name or ID)"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage logical groupings of physical resources where virtual machines run.", + "fields": [ + "id", + "url", + "display", + "name", + "type", + "group", + "tenant", + "site", + "status", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated", + "device_count", + "virtualmachine_count" + ], + }, + "cluster-groups": { + "endpoint": "virtualization/cluster-groups", + "filters": [ + {"name": "name", "description": "Filter by cluster group name"}, + {"name": "slug", "description": "Filter by cluster group slug"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Organize clusters into groups for better management.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "cluster_count" + ], + }, + "cluster-types": { + "endpoint": "virtualization/cluster-types", + "filters": [ + {"name": "name", "description": "Filter by cluster type name"}, + {"name": "slug", "description": "Filter by cluster type slug"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Define technologies or mechanisms by which clusters are formed.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "cluster_count" + ], + }, + "virtual-machines": { + "endpoint": "virtualization/virtual-machines", + "filters": [ + {"name": "name", "description": "Filter by virtual machine name"}, + {"name": "cluster_id", "description": "Filter by cluster ID"}, + {"name": "status", "description": "Filter by operational status"}, + {"name": "role", "description": "Filter by assigned role (name or ID)"}, + {"name": "platform", "description": "Filter by platform (name or ID)"}, + {"name": "tenant", "description": "Filter by tenant (name or ID)"}, + {"name": "primary_ip4", "description": "Filter by primary IPv4 address"}, + {"name": "primary_ip6", "description": "Filter by primary IPv6 address"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage virtual compute instances hosted within clusters.", + "fields": [ + "id", + "url", + "display", + "name", + "status", + "site", + "cluster", + "device", + "role", + "tenant", + "platform", + "primary_ip4", + "primary_ip6", + "vcpus", + "memory", + "disk", + "description", + "comments", + "config_context", + "local_context_data", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "vm-interfaces": { + "endpoint": "virtualization/interfaces", + "filters": [ + {"name": "name", "description": "Filter by interface name"}, + { + "name": "virtual_machine", + "description": "Filter by virtual machine (name or ID)", + }, + { + "name": "enabled", + "description": "Filter by enabled state (true or false)", + }, + {"name": "mac_address", "description": "Filter by MAC address"}, + {"name": "vrf", "description": "Filter by VRF (name or ID)"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage virtual interfaces assigned to virtual machines.", + "fields": [ + "id", + "url", + "display", + "virtual_machine", + "name", + "type", + "enabled", + "parent", + "bridge", + "mtu", + "mac_address", + "description", + "mode", + "untagged_vlan", + "tagged_vlans", + "vrf", + "l2vpn_termination", + "tags", + "custom_fields", + "created", + "last_updated", + "count_ipaddresses", + "count_fhrp_groups" + ], + }, + # Tenancy + "tenants": { + "endpoint": "tenancy/tenants", + "filters": [ + {"name": "name", "description": "Filter by tenant name"}, + {"name": "slug", "description": "Filter by tenant slug"}, + {"name": "group", "description": "Filter by tenant group (name or ID)"}, + {"name": "description", "description": "Filter by tenant description"}, + {"name": "comments", "description": "Filter by tenant comments"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage discrete groupings of resources used for administrative purposes, such as individual customers or internal departments.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "group", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated", + "circuit_count", + "device_count", + "ipaddress_count", + "prefix_count", + "rack_count", + "site_count", + "virtualmachine_count", + "vlan_count", + "vrf_count", + "cluster_count", + "contact_count" + ], + }, + "tenant-groups": { + "endpoint": "tenancy/tenant-groups", + "filters": [ + {"name": "name", "description": "Filter by tenant group name"}, + {"name": "slug", "description": "Filter by tenant group slug"}, + { + "name": "description", + "description": "Filter by tenant group description", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Organize tenants into hierarchical groups for better management and organization.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "parent", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "_depth", + "tenant_count" + ], + }, + "contacts": { + "endpoint": "tenancy/contacts", + "filters": [ + {"name": "name", "description": "Filter by contact name"}, + {"name": "title", "description": "Filter by contact title"}, + {"name": "phone", "description": "Filter by contact phone number"}, + {"name": "email", "description": "Filter by contact email address"}, + {"name": "address", "description": "Filter by contact physical address"}, + {"name": "group", "description": "Filter by contact group (name or ID)"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage individuals or points of contact responsible for various resources within the organization.", + "fields": [ + "id", + "url", + "display", + "name", + "title", + "phone", + "email", + "address", + "link", + "group", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated", + "assignments" + ], + }, + "contact-groups": { + "endpoint": "tenancy/contact-groups", + "filters": [ + {"name": "name", "description": "Filter by contact group name"}, + {"name": "slug", "description": "Filter by contact group slug"}, + { + "name": "description", + "description": "Filter by contact group description", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Organize contacts into hierarchical groups for better management and organization.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "parent", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "_depth", + "contact_count" + ], + }, + "contact-roles": { + "endpoint": "tenancy/contact-roles", + "filters": [ + {"name": "name", "description": "Filter by contact role name"}, + {"name": "slug", "description": "Filter by contact role slug"}, + { + "name": "description", + "description": "Filter by contact role description", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Define the relationship or responsibility a contact has with an assigned object, such as administrative, operational, or emergency roles.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "description", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + # VPN + "ike-policies": { + "endpoint": "vpn/ike-policies", + "filters": [ + {"name": "name", "description": "Filter by IKE policy name"}, + {"name": "version", "description": "Filter by IKE version (v1 or v2)"}, + { + "name": "mode", + "description": "Filter by mode (main or aggressive); applicable only for IKEv1", + }, + {"name": "proposals", "description": "Filter by associated IKE proposals"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage Internet Key Exchange (IKE) policies defining versions, modes, and associated proposals.", + "fields": [ + "id", + "url", + "display", + "name", + "version", + "mode", + "proposals", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "ike-proposals": { + "endpoint": "vpn/ike-proposals", + "filters": [ + {"name": "name", "description": "Filter by IKE proposal name"}, + { + "name": "authentication_method", + "description": "Filter by authentication method (e.g., pre-shared key, certificate)", + }, + { + "name": "encryption_algorithm", + "description": "Filter by encryption algorithm (e.g., AES, 3DES)", + }, + { + "name": "authentication_algorithm", + "description": "Filter by authentication algorithm (e.g., SHA256, MD5)", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage IKE proposals defining parameters for secure bidirectional connections.", + "fields": [ + "id", + "url", + "display", + "name", + "authentication_method", + "encryption_algorithm", + "authentication_algorithm", + "dh_group", + "description", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "ipsec-policies": { + "endpoint": "vpn/ipsec-policies", + "filters": [ + {"name": "name", "description": "Filter by IPSec policy name"}, + { + "name": "proposals", + "description": "Filter by associated IPSec proposals", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage IPSec policies defining sets of proposals for security associations.", + "fields": [ + "id", + "url", + "display", + "name", + "proposals", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "ipsec-profiles": { + "endpoint": "vpn/ipsec-profiles", + "filters": [ + {"name": "name", "description": "Filter by IPSec profile name"}, + {"name": "mode", "description": "Filter by IPSec mode (ESP or AH)"}, + {"name": "ike_policy", "description": "Filter by associated IKE policy"}, + { + "name": "ipsec_policy", + "description": "Filter by associated IPSec policy", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage IPSec profiles defining IKE policies, IPSec policies, and modes for tunnels.", + "fields": [ + "id", + "url", + "display", + "name", + "mode", + "ike_policy", + "ipsec_policy", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "ipsec-proposals": { + "endpoint": "vpn/ipsec-proposals", + "filters": [ + {"name": "name", "description": "Filter by IPSec proposal name"}, + { + "name": "encryption_algorithm", + "description": "Filter by encryption algorithm (e.g., AES, 3DES)", + }, + { + "name": "authentication_algorithm", + "description": "Filter by authentication algorithm (e.g., SHA256, MD5)", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage IPSec proposals defining parameters for negotiating security associations.", + "fields": [ + "id", + "url", + "display", + "name", + "encryption_algorithm", + "authentication_algorithm", + "sa_lifetime", + "description", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "l2vpns": { + "endpoint": "vpn/l2vpns", + "filters": [ + {"name": "name", "description": "Filter by L2VPN name"}, + {"name": "slug", "description": "Filter by L2VPN slug"}, + {"name": "type", "description": "Filter by L2VPN type (e.g., VPLS, VPWS)"}, + {"name": "identifier", "description": "Filter by L2VPN numeric identifier"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage Layer 2 Virtual Private Networks (L2VPNs) representing layer 2 bridge technologies.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "type", + "identifier", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated", + "terminations" + ], + }, + "tunnels": { + "endpoint": "vpn/tunnels", + "filters": [ + {"name": "name", "description": "Filter by tunnel name"}, + {"name": "type", "description": "Filter by tunnel type (e.g., GRE, IPSec)"}, + {"name": "status", "description": "Filter by operational status"}, + {"name": "group", "description": "Filter by tunnel group"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage private virtual connections established among endpoints using protocol encapsulation.", + "fields": [ + "id", + "url", + "display", + "name", + "tunnel_id", + "status", + "group", + "encapsulation", + "ipsec_profile", + "description", + "comments", + "tags", + "custom_fields", + "created", + "last_updated", + "termination_a", + "termination_z" + ], + }, + "tunnel-groups": { + "endpoint": "vpn/tunnel-groups", + "filters": [ + {"name": "name", "description": "Filter by tunnel group name"}, + {"name": "slug", "description": "Filter by tunnel group slug"}, + { + "name": "description", + "description": "Filter by tunnel group description", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Organize tunnels into groups for better management and organization.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "tunnel_count" + ], + }, + # Wireless + "wireless-lans": { + "endpoint": "wireless/wireless-lans", + "filters": [ + {"name": "ssid", "description": "Filter by Wireless LAN SSID"}, + { + "name": "group", + "description": "Filter by Wireless LAN Group (name or ID)", + }, + {"name": "status", "description": "Filter by operational status"}, + {"name": "vlan", "description": "Filter by associated VLAN (ID)"}, + { + "name": "authentication_type", + "description": "Filter by authentication type (e.g., open, wpa-personal)", + }, + { + "name": "authentication_cipher", + "description": "Filter by authentication cipher (e.g., auto, aes)", + }, + { + "name": "scope_type", + "description": "Filter by scope type (e.g., region, site)", + }, + {"name": "scope_id", "description": "Filter by scope ID"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage Wireless LANs (WLANs), representing sets of interfaces connected via a common wireless channel.", + "fields": [ + "id", + "url", + "display", + "ssid", + "description", + "group", + "status", + "vlan", + "tenant", + "auth_type", + "auth_cipher", + "auth_psk", + "scope_type", + "scope_id", + "scope", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, + "wireless-lan-groups": { + "endpoint": "wireless/wireless-lan-groups", + "filters": [ + {"name": "name", "description": "Filter by Wireless LAN Group name"}, + {"name": "slug", "description": "Filter by Wireless LAN Group slug"}, + { + "name": "parent", + "description": "Filter by parent Wireless LAN Group (ID)", + }, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Organize and classify Wireless LANs into hierarchical groups.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "parent", + "description", + "tags", + "custom_fields", + "created", + "last_updated", + "_depth", + "wireless_lan_count" + ], + }, + "wireless-links": { + "endpoint": "wireless/wireless-links", + "filters": [ + {"name": "interface_a", "description": "Filter by side A interface (ID)"}, + {"name": "interface_b", "description": "Filter by side B interface (ID)"}, + {"name": "status", "description": "Filter by operational status"}, + {"name": "ssid", "description": "Filter by SSID"}, + {"name": "auth_type", "description": "Filter by authentication type"}, + {"name": "auth_cipher", "description": "Filter by authentication cipher"}, + {"name": "tag", "description": "Filter by assigned tag"}, + ], + "description": "Manage point-to-point wireless links between exactly two wireless interfaces.", + "fields": [ + "id", + "url", + "display", + "ssid", + "status", + "tenant", + "auth_type", + "auth_cipher", + "auth_psk", + "description", + "interface_a", + "interface_b", + "tags", + "custom_fields", + "created", + "last_updated" + ], + }, +} diff --git a/server.py b/server.py index 98e58ee..7e8f690 100644 --- a/server.py +++ b/server.py @@ -1,112 +1,102 @@ +import os + from mcp.server.fastmcp import FastMCP +from typing import Dict, List, Optional + from netbox_client import NetBoxRestClient -import os -# Mapping of simple object names to API endpoints -NETBOX_OBJECT_TYPES = { - # DCIM (Device and Infrastructure) - "cables": "dcim/cables", - "console-ports": "dcim/console-ports", - "console-server-ports": "dcim/console-server-ports", - "devices": "dcim/devices", - "device-bays": "dcim/device-bays", - "device-roles": "dcim/device-roles", - "device-types": "dcim/device-types", - "front-ports": "dcim/front-ports", - "interfaces": "dcim/interfaces", - "inventory-items": "dcim/inventory-items", - "locations": "dcim/locations", - "manufacturers": "dcim/manufacturers", - "modules": "dcim/modules", - "module-bays": "dcim/module-bays", - "module-types": "dcim/module-types", - "platforms": "dcim/platforms", - "power-feeds": "dcim/power-feeds", - "power-outlets": "dcim/power-outlets", - "power-panels": "dcim/power-panels", - "power-ports": "dcim/power-ports", - "racks": "dcim/racks", - "rack-reservations": "dcim/rack-reservations", - "rack-roles": "dcim/rack-roles", - "regions": "dcim/regions", - "sites": "dcim/sites", - "site-groups": "dcim/site-groups", - "virtual-chassis": "dcim/virtual-chassis", - - # IPAM (IP Address Management) - "asns": "ipam/asns", - "asn-ranges": "ipam/asn-ranges", - "aggregates": "ipam/aggregates", - "fhrp-groups": "ipam/fhrp-groups", - "ip-addresses": "ipam/ip-addresses", - "ip-ranges": "ipam/ip-ranges", - "prefixes": "ipam/prefixes", - "rirs": "ipam/rirs", - "roles": "ipam/roles", - "route-targets": "ipam/route-targets", - "services": "ipam/services", - "vlans": "ipam/vlans", - "vlan-groups": "ipam/vlan-groups", - "vrfs": "ipam/vrfs", - - # Circuits - "circuits": "circuits/circuits", - "circuit-types": "circuits/circuit-types", - "circuit-terminations": "circuits/circuit-terminations", - "providers": "circuits/providers", - "provider-networks": "circuits/provider-networks", - - # Virtualization - "clusters": "virtualization/clusters", - "cluster-groups": "virtualization/cluster-groups", - "cluster-types": "virtualization/cluster-types", - "virtual-machines": "virtualization/virtual-machines", - "vm-interfaces": "virtualization/interfaces", - - # Tenancy - "tenants": "tenancy/tenants", - "tenant-groups": "tenancy/tenant-groups", - "contacts": "tenancy/contacts", - "contact-groups": "tenancy/contact-groups", - "contact-roles": "tenancy/contact-roles", - - # VPN - "ike-policies": "vpn/ike-policies", - "ike-proposals": "vpn/ike-proposals", - "ipsec-policies": "vpn/ipsec-policies", - "ipsec-profiles": "vpn/ipsec-profiles", - "ipsec-proposals": "vpn/ipsec-proposals", - "l2vpns": "vpn/l2vpns", - "tunnels": "vpn/tunnels", - "tunnel-groups": "vpn/tunnel-groups", - - # Wireless - "wireless-lans": "wireless/wireless-lans", - "wireless-lan-groups": "wireless/wireless-lan-groups", - "wireless-links": "wireless/wireless-links", - - # Extras - "config-contexts": "extras/config-contexts", - "custom-fields": "extras/custom-fields", - "export-templates": "extras/export-templates", - "image-attachments": "extras/image-attachments", - "jobs": "extras/jobs", - "saved-filters": "extras/saved-filters", - "scripts": "extras/scripts", - "tags": "extras/tags", - "webhooks": "extras/webhooks", -} +from .constants import API_ENDPOINTS + mcp = FastMCP("NetBox", log_level="DEBUG") netbox = None + +@mcp.tool() +def get_valid_filters(object_type: str) -> List[Dict[str, str]]: + """ + Retrieve valid filter keys and descriptions for a given NetBox object_type. + + Args: + object_type (str): The type of NetBox object to query. + Example values: "devices", "ip-addresses", "vlans", "virtual-machines", "tunnels", etc. + + Returns: + A list of valid filters and descriptions for that object type, each containing: + - name: The filter key + - description: What the filter does + + Example: + get_valid_filters("devices") → + [ + {"name": "name", "description": "Exact match on device name"}, + {"name": "site", "description": "Filter by Site slug"}, + ... + ] + + If the object_type is unknown or unsupported, returns an empty list. + + This should be used before calling get_objects if you are not sure what filters are + valid or available for that type. Use the "name" field to construct the filters. + """ + return API_ENDPOINTS.get(object_type, {}).get("filters", []) + + +@mcp.tool() +def get_fields(object_type: str) -> List[str]: + """ + Retrieve available fields for a given NetBox object_type. + + Args: + object_type (str): The type of NetBox object to query. + Example values: "devices", "ip-addresses", "vlans", "virtual-machines", "tunnels", etc. + + Returns: + A list of field names available for that object type. + + Example: + get_fields("devices") → + [ + "id", + "url", + "name", + "serial", + "asset_tag", + ... + ] + + If the object_type is unknown or unsupported, returns an empty list. + """ + return API_ENDPOINTS.get(object_type, {}).get("fields", []) + + +def call_netbox_api(endpoint_key: str, filters: dict = None): + """ + Generic function to call a NetBox API endpoint. + + Args: + endpoint_key (str): Key referencing the API_ENDPOINTS metadata + filters (dict, optional): Filtering parameters. Defaults to empty dict. + + Returns: + List[dict]: API response data + """ + endpoint_info = API_ENDPOINTS.get(endpoint_key) + if not endpoint_info: + raise ValueError(f"Unknown endpoint key: {endpoint_key}") + + endpoint = endpoint_info["endpoint"] + return netbox.get(endpoint, params=filters or {}) + + @mcp.tool() -def netbox_get_objects(object_type: str, filters: dict): +def netbox_get_objects(object_type: str, filters: Dict[str, str], fields: str = None): """ Get objects from NetBox based on their type and filters Args: object_type: String representing the NetBox object type (e.g. "devices", "ip-addresses") - filters: dict of filters to apply to the API call based on the NetBox API filtering options + filters (dict): Key-value filters to apply. Must match valid filter keys for the given object_type. + fields (str, optional): Comma-separated list of fields to include in response. If not specified, returns default fields. Valid object_type values: @@ -193,16 +183,18 @@ def netbox_get_objects(object_type: str, filters: dict): See NetBox API documentation for filtering options for each object type. """ - # Validate object_type exists in mapping - if object_type not in NETBOX_OBJECT_TYPES: - valid_types = "\n".join(f"- {t}" for t in sorted(NETBOX_OBJECT_TYPES.keys())) - raise ValueError(f"Invalid object_type. Must be one of:\n{valid_types}") - - # Get API endpoint from mapping - endpoint = NETBOX_OBJECT_TYPES[object_type] - - # Make API call - return netbox.get(endpoint, params=filters) + if object_type not in API_ENDPOINTS: + raise ValueError(f"Unsupported object_type: {object_type}") + + if not filters: + filters = {} + + filters["brief"] = 1 + if fields: + filters["fields"] = fields + + return call_netbox_api(object_type, filters or {}) + @mcp.tool() def netbox_get_object_by_id(object_type: str, object_id: int): @@ -217,15 +209,56 @@ def netbox_get_object_by_id(object_type: str, object_id: int): Complete object details """ # Validate object_type exists in mapping - if object_type not in NETBOX_OBJECT_TYPES: - valid_types = "\n".join(f"- {t}" for t in sorted(NETBOX_OBJECT_TYPES.keys())) + if object_type not in API_ENDPOINTS: + valid_types = "\n".join(f"- {t}" for t in sorted(API_ENDPOINTS.keys())) raise ValueError(f"Invalid object_type. Must be one of:\n{valid_types}") - + # Get API endpoint from mapping - endpoint = f"{NETBOX_OBJECT_TYPES[object_type]}/{object_id}" - + endpoint = f"{API_ENDPOINTS[object_type]['endpoint']}/{object_id}" + return netbox.get(endpoint) +@mcp.tool() +def get_object_by_name(object_type: str, object_name: str): + """ + Get detailed information about a specific NetBox object by its name. + + Args: + object_type: String representing the NetBox object type (e.g. "devices", "ip-addresses") + object_name: The name of the object + + Returns: + Complete object details + """ + # Validate object_type exists in mapping + if object_type not in API_ENDPOINTS: + valid_types = "\n".join(f"- {t}" for t in sorted(API_ENDPOINTS.keys())) + raise ValueError(f"Invalid object_type. Must be one of:\n{valid_types}") + + filters = {"q": object_name} + # Get API endpoint from mapping + data = call_netbox_api(object_type, filters or {}) + if len(data) == 1: + endpoint = f"{API_ENDPOINTS[object_type]['endpoint']}/{data[0]['id']}" + return netbox.get(endpoint) + + return data + + +@mcp.tool() +def slugify_name(object_name: str): + """ + Slugify a name to be used as a NetBox object name. + + Args: + object_name: The name to slugify + + Returns: + Slugified name + """ + return slugify(object_name) + + @mcp.tool() def netbox_get_changelogs(filters: dict): """ From 84a3e7c008abee5dfe27ae9fd58e760ce46f771c Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 7 May 2025 10:42:14 -0700 Subject: [PATCH 2/4] Add constants and new APIs --- constants.py | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++- server.py | 25 ++++++-- 2 files changed, 188 insertions(+), 6 deletions(-) diff --git a/constants.py b/constants.py index aaf04a0..8c879d1 100644 --- a/constants.py +++ b/constants.py @@ -1,4 +1,3 @@ - API_ENDPOINTS = { # DCIM "cables": { @@ -2394,4 +2393,172 @@ "last_updated" ], }, + # Customization + "custom-fields": { + "endpoint": "extras/custom-fields", + "filters": [ + {"name": "name", "description": "Name of the custom field"}, + {"name": "content_types", "description": "Content types this field applies to"}, + {"name": "type", "description": "Type of the custom field"}, + {"name": "required", "description": "Whether the field is required"}, + {"name": "filter_logic", "description": "Filter logic for the field"}, + {"name": "weight", "description": "Weight of the field"}, + {"name": "description", "description": "Description of the field"}, + {"name": "label", "description": "Label of the field"}, + {"name": "validation_regex", "description": "Validation regex for the field"}, + {"name": "choice_set", "description": "Choice set for the field"}, + {"name": "tag", "description": "Tag associated with the field"} + ], + "description": "Manage custom fields for NetBox objects.", + "fields": [ + "id", + "url", + "display", + "content_types", + "type", + "name", + "label", + "description", + "required", + "filter_logic", + "default", + "weight", + "validation_minimum", + "validation_maximum", + "validation_regex", + "choice_set", + "created", + "last_updated" + ] + }, + "custom-field-choice-sets": { + "endpoint": "extras/custom-field-choice-sets", + "filters": [ + {"name": "name", "description": "Name of the choice set"}, + {"name": "description", "description": "Description of the choice set"}, + {"name": "base_choices", "description": "Base choices for the set"}, + {"name": "extra_choices", "description": "Extra choices for the set"}, + {"name": "order_alphabetically", "description": "Whether to order choices alphabetically"}, + {"name": "tag", "description": "Tag associated with the choice set"} + ], + "description": "Manage choice sets for custom fields.", + "fields": [ + "id", + "url", + "display", + "name", + "description", + "base_choices", + "extra_choices", + "order_alphabetically", + "created", + "last_updated" + ] + }, + "custom-links": { + "endpoint": "extras/custom-links", + "filters": [ + {"name": "name", "description": "Name of the custom link"}, + {"name": "content_types", "description": "Content types this link applies to"}, + {"name": "enabled", "description": "Whether the link is enabled"}, + {"name": "link_text", "description": "Text of the link"}, + {"name": "link_url", "description": "URL of the link"}, + {"name": "weight", "description": "Weight of the link"}, + {"name": "group_name", "description": "Group name for the link"}, + {"name": "button_class", "description": "CSS class for the link button"}, + {"name": "new_window", "description": "Whether to open in new window"}, + {"name": "tag", "description": "Tag associated with the link"} + ], + "description": "Manage custom links for NetBox objects.", + "fields": [ + "id", + "url", + "display", + "content_types", + "name", + "enabled", + "link_text", + "link_url", + "weight", + "group_name", + "button_class", + "new_window", + "created", + "last_updated" + ] + }, + "export-templates": { + "endpoint": "extras/export-templates", + "filters": [ + {"name": "name", "description": "Name of the export template"}, + {"name": "content_types", "description": "Content types this template applies to"}, + {"name": "description", "description": "Description of the template"}, + {"name": "mime_type", "description": "MIME type of the template"}, + {"name": "file_extension", "description": "File extension for the template"}, + {"name": "as_attachment", "description": "Whether to serve as attachment"}, + {"name": "tag", "description": "Tag associated with the template"} + ], + "description": "Manage export templates for NetBox objects.", + "fields": [ + "id", + "url", + "display", + "content_types", + "name", + "description", + "template_code", + "mime_type", + "file_extension", + "as_attachment", + "created", + "last_updated" + ] + }, + "tags": { + "endpoint": "extras/tags", + "filters": [ + {"name": "name", "description": "Name of the tag"}, + {"name": "slug", "description": "Slug of the tag"}, + {"name": "color", "description": "Color of the tag"}, + {"name": "description", "description": "Description of the tag"} + ], + "description": "Manage tags for NetBox objects.", + "fields": [ + "id", + "url", + "display", + "name", + "slug", + "color", + "description", + "created", + "last_updated" + ] + }, + "image-attachments": { + "endpoint": "extras/image-attachments", + "filters": [ + {"name": "name", "description": "Name of the image attachment"}, + {"name": "content_type", "description": "Content type of the attachment"}, + {"name": "object_id", "description": "ID of the object"}, + {"name": "image", "description": "Image file"}, + {"name": "image_height", "description": "Height of the image"}, + {"name": "image_width", "description": "Width of the image"}, + {"name": "created", "description": "Creation date of the attachment"} + ], + "description": "Manage image attachments for NetBox objects.", + "fields": [ + "id", + "url", + "display", + "content_type", + "object_id", + "name", + "image", + "image_height", + "image_width", + "created", + "last_updated" + ] + } } diff --git a/server.py b/server.py index 7e8f690..f6effb2 100644 --- a/server.py +++ b/server.py @@ -1,13 +1,13 @@ import os +import re +import unicodedata +from typing import Dict, List from mcp.server.fastmcp import FastMCP -from typing import Dict, List, Optional +from constants import API_ENDPOINTS from netbox_client import NetBoxRestClient -from .constants import API_ENDPOINTS - - mcp = FastMCP("NetBox", log_level="DEBUG") netbox = None @@ -180,6 +180,14 @@ def netbox_get_objects(object_type: str, filters: Dict[str, str], fields: str = - wireless-lans - wireless-lan-groups - wireless-links + + Customization: + - custom-fields + - custom-field-choice-sets + - custom-links + - export-templates + - tags + - image-attachments See NetBox API documentation for filtering options for each object type. """ @@ -256,7 +264,14 @@ def slugify_name(object_name: str): Returns: Slugified name """ - return slugify(object_name) + value = str(object_name) + value = ( + unicodedata.normalize("NFKD", value) + .encode("ascii", "ignore") + .decode("ascii") + ) + value = re.sub(r"[^\w\s-]", "", value.lower()) + return re.sub(r"[-\s]+", "-", value).strip("-_") @mcp.tool() From abb5b2e95eab3afa93649f9ec5a7c8eee5c409fe Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 May 2025 14:34:02 -0700 Subject: [PATCH 3/4] add pagination --- server.py | 179 +++++++++++++++++++++++------------------------------- 1 file changed, 77 insertions(+), 102 deletions(-) diff --git a/server.py b/server.py index f6effb2..a9c24bc 100644 --- a/server.py +++ b/server.py @@ -13,7 +13,7 @@ @mcp.tool() -def get_valid_filters(object_type: str) -> List[Dict[str, str]]: +async def netbox_get_valid_filters(object_type: str) -> List[Dict[str, str]]: """ Retrieve valid filter keys and descriptions for a given NetBox object_type. @@ -43,7 +43,7 @@ def get_valid_filters(object_type: str) -> List[Dict[str, str]]: @mcp.tool() -def get_fields(object_type: str) -> List[str]: +async def netbox_get_fields(object_type: str) -> List[str]: """ Retrieve available fields for a given NetBox object_type. @@ -90,106 +90,42 @@ def call_netbox_api(endpoint_key: str, filters: dict = None): @mcp.tool() -def netbox_get_objects(object_type: str, filters: Dict[str, str], fields: str = None): +async def netbox_get_objects(object_type: str, filters: Dict[str, str], fields: str = None, limit: int = 25, offset: int = 0): """ - Get objects from NetBox based on their type and filters + Get objects from NetBox based on their type and filters with pagination support. + Args: object_type: String representing the NetBox object type (e.g. "devices", "ip-addresses") filters (dict): Key-value filters to apply. Must match valid filter keys for the given object_type. fields (str, optional): Comma-separated list of fields to include in response. If not specified, returns default fields. + limit (int, optional): Maximum number of objects to return per page. Defaults to 25. + offset (int, optional): Number of objects to skip before starting to collect the result set. Defaults to 0. - Valid object_type values: - - DCIM (Device and Infrastructure): - - cables - - console-ports - - console-server-ports - - devices - - device-bays - - device-roles - - device-types - - front-ports - - interfaces - - inventory-items - - locations - - manufacturers - - modules - - module-bays - - module-types - - platforms - - power-feeds - - power-outlets - - power-panels - - power-ports - - racks - - rack-reservations - - rack-roles - - regions - - sites - - site-groups - - virtual-chassis - - IPAM (IP Address Management): - - asns - - asn-ranges - - aggregates - - fhrp-groups - - ip-addresses - - ip-ranges - - prefixes - - rirs - - roles - - route-targets - - services - - vlans - - vlan-groups - - vrfs - - Circuits: - - circuits - - circuit-types - - circuit-terminations - - providers - - provider-networks - - Virtualization: - - clusters - - cluster-groups - - cluster-types - - virtual-machines - - vm-interfaces - - Tenancy: - - tenants - - tenant-groups - - contacts - - contact-groups - - contact-roles - - VPN: - - ike-policies - - ike-proposals - - ipsec-policies - - ipsec-profiles - - ipsec-proposals - - l2vpns - - tunnels - - tunnel-groups - - Wireless: - - wireless-lans - - wireless-lan-groups - - wireless-links - - Customization: - - custom-fields - - custom-field-choice-sets - - custom-links - - export-templates - - tags - - image-attachments - - See NetBox API documentation for filtering options for each object type. + Returns: + dict: A dictionary containing: + - count: Total number of objects matching the query + - next: URL for the next page of results (null if no next page) + - previous: URL for the previous page of results (null if no previous page) + - results: List of objects matching the query + + Example: + # Get first page of devices + netbox_get_objects( + object_type="devices", + filters={"site": "site-slug"}, + fields="id,name,status", + limit=25, + offset=0 + ) + + # Get second page of devices + netbox_get_objects( + object_type="devices", + filters={"site": "site-slug"}, + fields="id,name,status", + limit=25, + offset=25 + ) """ if object_type not in API_ENDPOINTS: raise ValueError(f"Unsupported object_type: {object_type}") @@ -200,12 +136,16 @@ def netbox_get_objects(object_type: str, filters: Dict[str, str], fields: str = filters["brief"] = 1 if fields: filters["fields"] = fields + + # Add pagination parameters + filters["limit"] = limit + filters["offset"] = offset return call_netbox_api(object_type, filters or {}) @mcp.tool() -def netbox_get_object_by_id(object_type: str, object_id: int): +async def netbox_get_object_by_id(object_type: str, object_id: int): """ Get detailed information about a specific NetBox object by its ID. @@ -227,7 +167,7 @@ def netbox_get_object_by_id(object_type: str, object_id: int): return netbox.get(endpoint) @mcp.tool() -def get_object_by_name(object_type: str, object_name: str): +async def netbox_get_object_by_name(object_type: str, object_name: str): """ Get detailed information about a specific NetBox object by its name. @@ -254,7 +194,7 @@ def get_object_by_name(object_type: str, object_name: str): @mcp.tool() -def slugify_name(object_name: str): +def netbox_slugify_name(object_name: str): """ Slugify a name to be used as a NetBox object name. @@ -275,15 +215,21 @@ def slugify_name(object_name: str): @mcp.tool() -def netbox_get_changelogs(filters: dict): +async def netbox_get_changelogs(filters: dict, limit: int = 25, offset: int = 0): """ - Get object change records (changelogs) from NetBox based on filters. + Get object change records (changelogs) from NetBox based on filters with pagination support. Args: filters: dict of filters to apply to the API call based on the NetBox API filtering options + limit (int, optional): Maximum number of changelog entries to return per page. Defaults to 25. + offset (int, optional): Number of changelog entries to skip before starting to collect the result set. Defaults to 0. Returns: - List of changelog objects matching the specified filters + dict: A dictionary containing: + - count: Total number of changelog entries matching the query + - next: URL for the next page of results (null if no next page) + - previous: URL for the previous page of results (null if no previous page) + - results: List of changelog entries matching the query Filtering options include: - user_id: Filter by user ID who made the change @@ -320,9 +266,38 @@ def netbox_get_changelogs(filters: dict): """ endpoint = "core/object-changes" + # Add pagination parameters to filters + filters["limit"] = limit + filters["offset"] = offset + # Make API call return netbox.get(endpoint, params=filters) + +@mcp.tool() +async def netbox_get_valid_object_types() -> List[Dict[str, str]]: + """ + Retrieve a list of all valid NetBox object types and their descriptions. + + Returns: + A list of dictionaries containing: + - name: The object type key + - description: Description of what the object type represents + + Example: + netbox_get_valid_object_types() → + [ + {"name": "devices", "description": "Manage devices such as routers, switches, servers, and more."}, + {"name": "ip-addresses", "description": "Manage individual IP addresses and their assignments."}, + ... + ] + """ + return [ + {"name": key, "description": value["description"]} + for key, value in API_ENDPOINTS.items() + ] + + if __name__ == "__main__": # Load NetBox configuration from environment variables netbox_url = os.getenv("NETBOX_URL") From 7d703be799aaaa094d674375a1d77db31a22fb2e Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 19 May 2025 14:55:35 -0700 Subject: [PATCH 4/4] add codeowners --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..3a92518 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @arthanson @jnovinger @bctiemann @jeremystretch