Skip to content
Snippets Groups Projects
Verified Commit e281d0ce authored by Karel van Klink's avatar Karel van Klink :smiley_cat:
Browse files

Add update and delete methods for Kentik device API

parent ca073287
No related branches found
No related tags found
No related merge requests found
...@@ -4,13 +4,29 @@ import logging ...@@ -4,13 +4,29 @@ import logging
from typing import Any from typing import Any
import requests import requests
from pydantic import BaseModel
from requests import Response
from gso.products.product_types.router import Router from gso.products.product_blocks.site import SiteTier
from gso.settings import load_oss_params from gso.settings import load_oss_params
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class NewKentikDevice(BaseModel):
"""API model for creating a new device in Kentik."""
device_name: str
device_description: str
sending_ips: list[str]
site_id: int
site_tier: SiteTier
device_snmp_ip: str
device_bgp_flowspec: bool
device_bgp_neighbor_ip: str
device_bgp_neighbor_ip6: str
class KentikClient: class KentikClient:
"""The client for Kentik that interacts with an external instance.""" """The client for Kentik that interacts with an external instance."""
...@@ -23,19 +39,21 @@ class KentikClient: ...@@ -23,19 +39,21 @@ class KentikClient:
"Content-Type": "application/json", "Content-Type": "application/json",
} }
def _send_request(self, method, endpoint: str, data: dict[str, Any] | None = None) -> dict[str, Any]: def _send_request(self, method, endpoint: str, data: dict[str, Any] | None = None) -> Response:
url = self.config.api_base + endpoint url = self.config.api_base + endpoint
logger.debug("Kentik - Sending request", extra={"method": method, "endpoint": url, "form_data": data})
result = requests.request(method, url, json=data, headers=self.headers) result = requests.request(method, url, json=data, headers=self.headers)
logger.debug("Kentik - Received response", extra=result.__dict__)
return result.json() return result
def get_devices(self) -> list[dict[str, Any]]: def get_devices(self) -> list[dict[str, Any]]:
"""List all devices in Kentik.""" """List all devices in Kentik."""
return [self._send_request("GET", "v5/devices")] return [self._send_request("GET", "v5/devices").json()]
def get_device(self, device_id: str) -> dict[str, Any]: def get_device(self, device_id: str) -> dict[str, Any]:
"""Get a device by ID.""" """Get a device by ID."""
return self._send_request("GET", f"v5/device/{device_id}") return self._send_request("GET", f"v5/device/{device_id}").json()
def get_device_by_name(self, device_name: str) -> dict[str, Any]: def get_device_by_name(self, device_name: str) -> dict[str, Any]:
"""Fetch a device in Kentik by its :term:`FQDN`. """Fetch a device in Kentik by its :term:`FQDN`.
...@@ -53,11 +71,11 @@ class KentikClient: ...@@ -53,11 +71,11 @@ class KentikClient:
def get_sites(self) -> list[dict[str, Any]]: def get_sites(self) -> list[dict[str, Any]]:
"""Get a list of all available sites in Kentik.""" """Get a list of all available sites in Kentik."""
return self._send_request("GET", "v5/sites")["sites"] return self._send_request("GET", "v5/sites").json()["sites"]
def get_site(self, site_id: str) -> dict[str, Any]: def get_site(self, site_id: str) -> dict[str, Any]:
"""Get a site by ID.""" """Get a site by ID."""
return self._send_request("GET", f"v5/site/{site_id}") return self._send_request("GET", f"v5/site/{site_id}").json()
def get_site_by_name(self, site_slug: str) -> dict[str, Any]: def get_site_by_name(self, site_slug: str) -> dict[str, Any]:
"""Get a Kentik site by its name. """Get a Kentik site by its name.
...@@ -75,7 +93,7 @@ class KentikClient: ...@@ -75,7 +93,7 @@ class KentikClient:
def get_plans(self) -> list[dict[str, Any]]: def get_plans(self) -> list[dict[str, Any]]:
"""Get all Kentik plans available.""" """Get all Kentik plans available."""
return self._send_request("GET", "v5/plans")["plans"] return self._send_request("GET", "v5/plans").json()["plans"]
def get_plan_by_name(self, plan_name: str) -> dict[str, Any]: def get_plan_by_name(self, plan_name: str) -> dict[str, Any]:
"""Get a Kentik plan by its name. """Get a Kentik plan by its name.
...@@ -91,31 +109,38 @@ class KentikClient: ...@@ -91,31 +109,38 @@ class KentikClient:
return {} return {}
def create_device(self, router: Router) -> dict[str, Any]: def create_device(self, device: NewKentikDevice) -> dict[str, Any]:
"""Add a new device to Kentik.""" """Add a new device to Kentik."""
site_id = self.get_site_by_name(router.router.router_site.site_name)["id"] plan_id = self.get_plan_by_name(self.config.billing_plans[device.site_tier])["id"]
plan_id = self.get_plan_by_name(self.config.billing_plans[router.router.router_site.site_tier])
request_body = { request_body = {
"device": { "device": {
# Route selection missing **device.model_dump(exclude=set("site_tier")),
"deviceName": router.router.router_fqdn, "device_type": self.config.device_type,
"deviceSubtype": self.config.device_type, "device_subtype": self.config.device_type,
"sendingIps": [str(router.router.router_lo_ipv4_address)], "minimize_snmp": self.config.minimize_snmp,
"deviceSampleRate": self.config.sample_rate, "device_sample_rate": self.config.sample_rate,
"planId": plan_id, "plan_id": plan_id,
"siteId": site_id, "device_snmp_community": self.config.snmp_community,
"deviceSnmpIp": str(router.router.router_lo_ipv4_address), "device_bgp_type": self.config.bgp_type,
"deviceSnmpCommunity": self.config.snmp_community, "bgp_lookup_strategy": self.config.bgp_lookup_strategy,
"deviceBgpType": self.config.bgp_type, "device_bgp_neighbor_asn": str(self.config.ASN),
"deviceBgpFlowspec": False, "device_bgp_password": self.config.md5_password,
"deviceBgpNeighborIp": str(router.router.router_lo_ipv4_address),
"deviceBgpNeighborIp6": str(router.router.router_lo_ipv6_address),
"deviceBgpNeighborAsn": str(self.config.ASN),
"deviceBgpPassword": self.config.md5_password,
} }
} }
return self._send_request("POST", "v5/device", request_body) return self._send_request("POST", "v5/device", request_body).json()
def update_device(self, device_id: str, updated_device: dict[str, Any]) -> dict[str, Any]:
"""Update an existing device in Kentik."""
return self._send_request("PUT", f"v5/device/{device_id}", updated_device).json()
def remove_device(self, device_id: str, *, archive: bool = True) -> None:
"""Remove a device from Kentik.
:param str device_id: The Kentik internal ID of the device that is to be removed.
:param bool archive: Archive the device instead of completely deleting it.
"""
if not archive:
self._send_request("DELETE", f"v5/device/{device_id}")
def remove_device(self, hostname: str) -> None: self._send_request("DELETE", f"v5/device/{device_id}")
"""Remove a device from Kentik."""
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment