From 6c55a147295f583573f8e983f5b550025f9f6e6c Mon Sep 17 00:00:00 2001
From: Karel van Klink <karel.vanklink@geant.org>
Date: Tue, 15 Oct 2024 11:44:13 +0200
Subject: [PATCH] don't fail router termination if the device doesn't exist in
 LibreNMS or Kentik

---
 gso/services/netbox_client.py            |  2 +-
 gso/services/subscriptions.py            |  3 +--
 gso/settings.py                          |  3 ++-
 gso/utils/types/netbox_router.py         |  2 +-
 gso/workflows/router/terminate_router.py | 18 ++++++++++--------
 gso/workflows/router/validate_router.py  |  2 +-
 gso/workflows/tasks/delete_partners.py   |  3 +--
 gso/workflows/tasks/modify_partners.py   |  3 +--
 8 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/gso/services/netbox_client.py b/gso/services/netbox_client.py
index 570ecbeb..b79283cc 100644
--- a/gso/services/netbox_client.py
+++ b/gso/services/netbox_client.py
@@ -5,7 +5,7 @@ from uuid import UUID
 
 import pydantic
 import pynetbox
-from pydantic_forms.types import UUIDstr
+from orchestrator.types import UUIDstr
 from pynetbox.models.dcim import Devices, DeviceTypes, Interfaces
 
 from gso.products.product_types.router import Router
diff --git a/gso/services/subscriptions.py b/gso/services/subscriptions.py
index 8a8bcf98..33db8fd9 100644
--- a/gso/services/subscriptions.py
+++ b/gso/services/subscriptions.py
@@ -18,8 +18,7 @@ from orchestrator.db import (
 )
 from orchestrator.domain import SubscriptionModel
 from orchestrator.services.subscriptions import query_in_use_by_subscriptions
-from orchestrator.types import SubscriptionLifecycle
-from pydantic_forms.types import UUIDstr
+from orchestrator.types import SubscriptionLifecycle, UUIDstr
 
 from gso.products import ProductName, ProductType
 from gso.products.product_types.site import Site
diff --git a/gso/settings.py b/gso/settings.py
index f7d40de7..b7b62186 100644
--- a/gso/settings.py
+++ b/gso/settings.py
@@ -11,8 +11,9 @@ import os
 from pathlib import Path
 from typing import Annotated
 
+from orchestrator.types import UUIDstr
 from pydantic import EmailStr, Field
-from pydantic_forms.types import UUIDstr, strEnum
+from pydantic_forms.types import strEnum
 from pydantic_settings import BaseSettings
 from typing_extensions import Doc
 
diff --git a/gso/utils/types/netbox_router.py b/gso/utils/types/netbox_router.py
index 2a302b56..8ea14aa4 100644
--- a/gso/utils/types/netbox_router.py
+++ b/gso/utils/types/netbox_router.py
@@ -2,8 +2,8 @@
 
 from typing import Annotated, TypeVar
 
+from orchestrator.types import UUIDstr
 from pydantic import AfterValidator
-from pydantic_forms.types import UUIDstr
 
 from gso.products.product_types.router import Router
 from gso.services.netbox_client import NetboxClient
diff --git a/gso/workflows/router/terminate_router.py b/gso/workflows/router/terminate_router.py
index 13cef223..ad374f23 100644
--- a/gso/workflows/router/terminate_router.py
+++ b/gso/workflows/router/terminate_router.py
@@ -3,13 +3,11 @@
 import ipaddress
 import json
 import logging
-from typing import Any
 
 from orchestrator.forms import FormPage
 from orchestrator.forms.validators import Label
 from orchestrator.targets import Target
-from orchestrator.types import FormGenerator, SubscriptionLifecycle, UUIDstr
-from orchestrator.utils.errors import ProcessFailureError
+from orchestrator.types import FormGenerator, State, SubscriptionLifecycle, UUIDstr
 from orchestrator.utils.json import json_dumps
 from orchestrator.workflow import StepList, begin, conditional, done, step, workflow
 from orchestrator.workflows.steps import (
@@ -19,6 +17,7 @@ from orchestrator.workflows.steps import (
     unsync,
 )
 from orchestrator.workflows.utils import wrap_modify_initial_input_form
+from requests import HTTPError
 
 from gso.products.product_blocks.router import RouterRole
 from gso.products.product_types.router import Router
@@ -224,13 +223,17 @@ def remove_pe_from_all_p_real(subscription: Router, tt_number: str, process_id:
 
 
 @step("Remove Device from Librenms")
-def remove_device_from_librenms(subscription: Router) -> None:
+def remove_device_from_librenms(subscription: Router) -> State | None:
     """Remove the device from LibreNMS."""
-    LibreNMSClient().remove_device(subscription.router.router_fqdn)
+    try:
+        LibreNMSClient().remove_device(subscription.router.router_fqdn)
+    except HTTPError as e:
+        return {"librenms_error": str(e)}
+    return None
 
 
 @step("Apply the archiving license in Kentik")
-def kentik_apply_archive_license(subscription: Router) -> dict[str, dict[str, Any]]:
+def kentik_apply_archive_license(subscription: Router) -> State:
     """Apply the archiving license to a PE router in Kentik.
 
     This includes setting the flow rate to one flow per second.
@@ -239,8 +242,7 @@ def kentik_apply_archive_license(subscription: Router) -> dict[str, dict[str, An
     kentik_archive_plan_id = kentik_client.get_plan_by_name(load_oss_params().KENTIK.archive_license_key)["id"]
     kentik_device = kentik_client.get_device_by_name(subscription.router.router_fqdn)
     if "id" not in kentik_device:
-        msg = "Failed to find Kentik device by name"
-        raise ProcessFailureError(msg, details=kentik_device)
+        return {"kentik_device": "Device not found, no license applied"}
 
     updated_device = {"device": {"plan_id": kentik_archive_plan_id, "device_sample_rate": 1}}
     kentik_device = kentik_client.update_device(kentik_device["id"], updated_device)
diff --git a/gso/workflows/router/validate_router.py b/gso/workflows/router/validate_router.py
index 9e13f521..ab6e3059 100644
--- a/gso/workflows/router/validate_router.py
+++ b/gso/workflows/router/validate_router.py
@@ -3,11 +3,11 @@
 from typing import Any
 
 from orchestrator.targets import Target
+from orchestrator.types import State, UUIDstr
 from orchestrator.utils.errors import ProcessFailureError
 from orchestrator.workflow import StepList, begin, conditional, done, step, workflow
 from orchestrator.workflows.steps import resync, store_process_subscription, unsync
 from orchestrator.workflows.utils import wrap_modify_initial_input_form
-from pydantic_forms.types import State, UUIDstr
 
 from gso.products.product_blocks.router import RouterRole
 from gso.products.product_types.router import Router
diff --git a/gso/workflows/tasks/delete_partners.py b/gso/workflows/tasks/delete_partners.py
index cd06cc06..6eac752b 100644
--- a/gso/workflows/tasks/delete_partners.py
+++ b/gso/workflows/tasks/delete_partners.py
@@ -4,10 +4,9 @@ from enum import Enum
 
 from orchestrator.forms import FormPage
 from orchestrator.targets import Target
-from orchestrator.types import FormGenerator, State
+from orchestrator.types import FormGenerator, State, UUIDstr
 from orchestrator.workflow import StepList, begin, done, step, workflow
 from pydantic import ConfigDict, EmailStr, field_validator
-from pydantic_forms.types import UUIDstr
 from pydantic_forms.validators import Choice
 
 from gso.services.partners import delete_partner, get_all_partners, get_partner_by_name
diff --git a/gso/workflows/tasks/modify_partners.py b/gso/workflows/tasks/modify_partners.py
index 46f912cc..cb2dadda 100644
--- a/gso/workflows/tasks/modify_partners.py
+++ b/gso/workflows/tasks/modify_partners.py
@@ -2,10 +2,9 @@
 
 from orchestrator.forms import FormPage
 from orchestrator.targets import Target
-from orchestrator.types import FormGenerator, State
+from orchestrator.types import FormGenerator, State, UUIDstr
 from orchestrator.workflow import StepList, begin, done, step, workflow
 from pydantic import ConfigDict, EmailStr, field_validator
-from pydantic_forms.types import UUIDstr
 from pydantic_forms.validators import Choice
 
 from gso.services.partners import (
-- 
GitLab