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

Add a router to Kentik when creating with a PE role

parent 75384f00
No related branches found
No related tags found
1 merge request!309Add a router to Kentik when creating with a PE role
Pipeline #90508 failed
...@@ -6,6 +6,7 @@ from typing import Any ...@@ -6,6 +6,7 @@ from typing import Any
from orchestrator import inputstep, step from orchestrator import inputstep, step
from orchestrator.config.assignee import Assignee from orchestrator.config.assignee import Assignee
from orchestrator.types import State, UUIDstr from orchestrator.types import State, UUIDstr
from orchestrator.utils.errors import ProcessFailureError
from orchestrator.utils.json import json_dumps from orchestrator.utils.json import json_dumps
from orchestrator.workflow import StepList, conditional from orchestrator.workflow import StepList, conditional
from pydantic import ConfigDict from pydantic import ConfigDict
...@@ -15,6 +16,7 @@ from pydantic_forms.validators import Label ...@@ -15,6 +16,7 @@ from pydantic_forms.validators import Label
from gso.products.product_blocks.router import RouterRole from gso.products.product_blocks.router import RouterRole
from gso.products.product_types.iptrunk import Iptrunk from gso.products.product_types.iptrunk import Iptrunk
from gso.services.kentik_client import KentikClient, NewKentikDevice
from gso.services.lso_client import LSOState, indifferent_lso_interaction from gso.services.lso_client import LSOState, indifferent_lso_interaction
from gso.settings import load_oss_params from gso.settings import load_oss_params
from gso.utils.helpers import generate_inventory_for_active_routers from gso.utils.helpers import generate_inventory_for_active_routers
...@@ -423,3 +425,28 @@ def stop_moodi() -> StepList: ...@@ -423,3 +425,28 @@ def stop_moodi() -> StepList:
} }
return _is_moodi_enabled(indifferent_lso_interaction(_stop_moodi)) return _is_moodi_enabled(indifferent_lso_interaction(_stop_moodi))
@step("Create Kentik device")
def create_kentik_device(state: State) -> State:
"""Create a new device in Kentik."""
kentik_client = KentikClient()
kentik_site = kentik_client.get_site_by_name(state["subscription"]["router"]["router_site"]["site_name"])
if not kentik_site:
msg = "Site could not be found in Kentik."
raise ProcessFailureError(msg, details=state["subscription"]["router"]["router_site"]["site_name"])
new_device = NewKentikDevice(
device_name=state["subscription"]["router"]["router_fqdn"],
device_description=str(state["subscription"]["subscription_id"]),
sending_ips=[str(state["subscription"]["router"]["router_lo_ipv4_address"])],
site_id=kentik_site["id"],
device_snmp_ip=str(state["subscription"]["router"]["router_lo_ipv4_address"]),
device_bgp_flowspec=False,
device_bgp_neighbor_ip=str(state["subscription"]["router"]["router_lo_ipv4_address"]),
device_bgp_neighbor_ip6=str(state["subscription"]["router"]["router_lo_ipv6_address"]),
)
kentik_device = kentik_client.create_device(new_device)
return {"kentik_device": kentik_device}
...@@ -28,6 +28,7 @@ from gso.utils.shared_enums import Vendor ...@@ -28,6 +28,7 @@ from gso.utils.shared_enums import Vendor
from gso.utils.types.ip_address import PortNumber from gso.utils.types.ip_address import PortNumber
from gso.utils.types.tt_number import TTNumber from gso.utils.types.tt_number import TTNumber
from gso.utils.workflow_steps import ( from gso.utils.workflow_steps import (
create_kentik_device,
deploy_base_config_dry, deploy_base_config_dry,
deploy_base_config_real, deploy_base_config_real,
prompt_sharepoint_checklist_url, prompt_sharepoint_checklist_url,
...@@ -254,6 +255,7 @@ def create_router() -> StepList: ...@@ -254,6 +255,7 @@ def create_router() -> StepList:
* Create a new device in Netbox * Create a new device in Netbox
""" """
router_is_nokia = conditional(lambda state: state["vendor"] == Vendor.NOKIA) router_is_nokia = conditional(lambda state: state["vendor"] == Vendor.NOKIA)
router_is_pe = conditional(lambda state: state["router_role"] == RouterRole.PE)
return ( return (
begin begin
...@@ -261,6 +263,7 @@ def create_router() -> StepList: ...@@ -261,6 +263,7 @@ def create_router() -> StepList:
>> store_process_subscription(Target.CREATE) >> store_process_subscription(Target.CREATE)
>> initialize_subscription >> initialize_subscription
>> ipam_allocate_loopback >> ipam_allocate_loopback
>> router_is_pe(create_kentik_device)
>> lso_interaction(deploy_base_config_dry) >> lso_interaction(deploy_base_config_dry)
>> lso_interaction(deploy_base_config_real) >> lso_interaction(deploy_base_config_real)
>> verify_ipam_loopback >> verify_ipam_loopback
......
...@@ -8,7 +8,6 @@ from orchestrator.forms import FormPage ...@@ -8,7 +8,6 @@ from orchestrator.forms import FormPage
from orchestrator.forms.validators import Label from orchestrator.forms.validators import Label
from orchestrator.targets import Target from orchestrator.targets import Target
from orchestrator.types import FormGenerator, State, UUIDstr from orchestrator.types import FormGenerator, State, UUIDstr
from orchestrator.utils.errors import ProcessFailureError
from orchestrator.utils.json import json_dumps from orchestrator.utils.json import json_dumps
from orchestrator.workflow import StepList, begin, done, inputstep, step, workflow from orchestrator.workflow import StepList, begin, done, inputstep, step, workflow
from orchestrator.workflows.steps import resync, store_process_subscription, unsync from orchestrator.workflows.steps import resync, store_process_subscription, unsync
...@@ -17,7 +16,6 @@ from pydantic import ConfigDict, model_validator ...@@ -17,7 +16,6 @@ from pydantic import ConfigDict, model_validator
from gso.products.product_blocks.router import RouterRole from gso.products.product_blocks.router import RouterRole
from gso.products.product_types.router import Router from gso.products.product_types.router import Router
from gso.services.kentik_client import KentikClient, NewKentikDevice
from gso.services.lso_client import LSOState, lso_interaction from gso.services.lso_client import LSOState, lso_interaction
from gso.services.subscriptions import get_all_active_sites from gso.services.subscriptions import get_all_active_sites
from gso.utils.helpers import generate_inventory_for_active_routers from gso.utils.helpers import generate_inventory_for_active_routers
...@@ -34,6 +32,7 @@ from gso.utils.workflow_steps import ( ...@@ -34,6 +32,7 @@ from gso.utils.workflow_steps import (
add_pe_to_pe_mesh_real, add_pe_to_pe_mesh_real,
check_l3_services, check_l3_services,
check_pe_ibgp, check_pe_ibgp,
create_kentik_device,
update_sdp_mesh_dry, update_sdp_mesh_dry,
update_sdp_mesh_real, update_sdp_mesh_real,
) )
...@@ -130,40 +129,6 @@ def prompt_insert_in_earl(subscription: dict[str, Any]) -> FormGenerator: ...@@ -130,40 +129,6 @@ def prompt_insert_in_earl(subscription: dict[str, Any]) -> FormGenerator:
return {} return {}
@step("Create Kentik device")
def create_kentik_device(subscription: Router) -> State:
"""Create a new device in Kentik."""
if not (
subscription.router.router_site
and subscription.router.router_site.site_name
and subscription.router.router_site.site_tier
and subscription.router.router_fqdn
):
msg = "Router object is missing required properties."
raise ProcessFailureError(msg)
kentik_client = KentikClient()
kentik_site = kentik_client.get_site_by_name(subscription.router.router_site.site_name)
if not kentik_site:
msg = "Site could not be found in Kentik."
raise ProcessFailureError(msg, details=subscription.router.router_site.site_name)
new_device = NewKentikDevice(
device_name=subscription.router.router_fqdn,
device_description=str(subscription.subscription_id),
sending_ips=[str(subscription.router.router_lo_ipv4_address)],
site_id=kentik_site["id"],
device_snmp_ip=str(subscription.router.router_lo_ipv4_address),
device_bgp_flowspec=False,
device_bgp_neighbor_ip=str(subscription.router.router_lo_ipv4_address),
device_bgp_neighbor_ip6=str(subscription.router.router_lo_ipv6_address),
)
kentik_device = kentik_client.create_device(new_device)
return {"kentik_device": kentik_device}
@step("[DRY RUN] Remove P from all PEs") @step("[DRY RUN] Remove P from all PEs")
def remove_p_from_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState: def remove_p_from_pe_dry(subscription: dict[str, Any], tt_number: str, process_id: UUIDstr) -> LSOState:
"""Perform a dry run of removing the P router from all the PE routers.""" """Perform a dry run of removing the P router from all the PE routers."""
......
...@@ -10,7 +10,7 @@ from gso.products.product_types.site import Site ...@@ -10,7 +10,7 @@ from gso.products.product_types.site import Site
from gso.services.subscriptions import get_product_id_by_name from gso.services.subscriptions import get_product_id_by_name
from gso.utils.shared_enums import Vendor from gso.utils.shared_enums import Vendor
from test import USER_CONFIRM_EMPTY_FORM from test import USER_CONFIRM_EMPTY_FORM
from test.services.conftest import MockedSharePointClient from test.services.conftest import MockedKentikClient, MockedSharePointClient
from test.workflows import ( from test.workflows import (
assert_complete, assert_complete,
assert_lso_interaction_failure, assert_lso_interaction_failure,
...@@ -31,19 +31,21 @@ def router_creation_input_form_data(site_subscription_factory, faker): ...@@ -31,19 +31,21 @@ def router_creation_input_form_data(site_subscription_factory, faker):
"router_site": router_site, "router_site": router_site,
"hostname": faker.pystr(), "hostname": faker.pystr(),
"ts_port": faker.pyint(), "ts_port": faker.pyint(),
"router_role": faker.random_choices(elements=(RouterRole.P, RouterRole.PE, RouterRole.AMT), length=1)[0],
"vendor": Vendor.NOKIA, "vendor": Vendor.NOKIA,
} }
@pytest.mark.workflow() @pytest.mark.workflow()
@pytest.mark.parametrize("router_role", [RouterRole.P, RouterRole.PE])
@patch("gso.services.lso_client._send_request") @patch("gso.services.lso_client._send_request")
@patch("gso.workflows.router.create_router.NetboxClient.create_device") @patch("gso.workflows.router.create_router.NetboxClient.create_device")
@patch("gso.workflows.router.create_router.infoblox.hostname_available") @patch("gso.workflows.router.create_router.infoblox.hostname_available")
@patch("gso.workflows.router.create_router.infoblox.find_host_by_fqdn") @patch("gso.workflows.router.create_router.infoblox.find_host_by_fqdn")
@patch("gso.workflows.router.create_router.infoblox.allocate_host") @patch("gso.workflows.router.create_router.infoblox.allocate_host")
@patch("gso.workflows.router.create_router.SharePointClient") @patch("gso.workflows.router.create_router.SharePointClient")
@patch("gso.utils.workflow_steps.KentikClient")
def test_create_nokia_router_success( def test_create_nokia_router_success(
mock_kentik_client,
mock_sharepoint_client, mock_sharepoint_client,
mock_allocate_host, mock_allocate_host,
mock_find_host_by_fqdn, mock_find_host_by_fqdn,
...@@ -51,10 +53,11 @@ def test_create_nokia_router_success( ...@@ -51,10 +53,11 @@ def test_create_nokia_router_success(
mock_netbox_create_device, mock_netbox_create_device,
mock_provision_router, mock_provision_router,
router_creation_input_form_data, router_creation_input_form_data,
router_role,
faker, faker,
data_config_filename,
): ):
# Set up mock return values # Set up mock return values
mock_kentik_client.return_value = MockedKentikClient
product_id = get_product_id_by_name(ProductName.ROUTER) product_id = get_product_id_by_name(ProductName.ROUTER)
mock_site = Site.from_subscription(router_creation_input_form_data["router_site"]).site mock_site = Site.from_subscription(router_creation_input_form_data["router_site"]).site
mock_v4 = faker.ipv4() mock_v4 = faker.ipv4()
...@@ -68,7 +71,7 @@ def test_create_nokia_router_success( ...@@ -68,7 +71,7 @@ def test_create_nokia_router_success(
mock_sharepoint_client.return_value = MockedSharePointClient mock_sharepoint_client.return_value = MockedSharePointClient
# Run workflow # Run workflow
initial_router_data = [{"product": product_id}, router_creation_input_form_data, {}] initial_router_data = [{"product": product_id}, router_creation_input_form_data | {"router_role": router_role}, {}]
result, process_stat, step_log = run_workflow("create_router", initial_router_data) result, process_stat, step_log = run_workflow("create_router", initial_router_data)
state = extract_state(result) state = extract_state(result)
...@@ -118,6 +121,7 @@ def test_create_nokia_router_success( ...@@ -118,6 +121,7 @@ def test_create_nokia_router_success(
@pytest.mark.workflow() @pytest.mark.workflow()
@pytest.mark.parametrize("router_role", [RouterRole.P, RouterRole.PE])
@patch("gso.services.lso_client._send_request") @patch("gso.services.lso_client._send_request")
@patch("gso.workflows.router.create_router.NetboxClient.create_device") @patch("gso.workflows.router.create_router.NetboxClient.create_device")
@patch("gso.workflows.router.create_router.infoblox.hostname_available") @patch("gso.workflows.router.create_router.infoblox.hostname_available")
...@@ -126,7 +130,9 @@ def test_create_nokia_router_success( ...@@ -126,7 +130,9 @@ def test_create_nokia_router_success(
@patch("gso.workflows.router.create_router.infoblox.allocate_v6_network") @patch("gso.workflows.router.create_router.infoblox.allocate_v6_network")
@patch("gso.workflows.router.create_router.infoblox.allocate_v4_network") @patch("gso.workflows.router.create_router.infoblox.allocate_v4_network")
@patch("gso.workflows.router.create_router.infoblox.allocate_host") @patch("gso.workflows.router.create_router.infoblox.allocate_host")
@patch("gso.utils.workflow_steps.KentikClient")
def test_create_nokia_router_lso_failure( def test_create_nokia_router_lso_failure(
mock_kentik_client,
mock_allocate_host, mock_allocate_host,
mock_allocate_v4_network, mock_allocate_v4_network,
mock_allocate_v6_network, mock_allocate_v6_network,
...@@ -136,9 +142,11 @@ def test_create_nokia_router_lso_failure( ...@@ -136,9 +142,11 @@ def test_create_nokia_router_lso_failure(
mock_netbox_create_device, mock_netbox_create_device,
mock_provision_router, mock_provision_router,
router_creation_input_form_data, router_creation_input_form_data,
router_role,
faker, faker,
): ):
# Set up mock return values # Set up mock return values
mock_kentik_client.return_value = MockedKentikClient
mock_site = Site.from_subscription(router_creation_input_form_data["router_site"]).site mock_site = Site.from_subscription(router_creation_input_form_data["router_site"]).site
mock_v4 = faker.ipv4() mock_v4 = faker.ipv4()
mock_v4_net = faker.ipv4(network=True) mock_v4_net = faker.ipv4(network=True)
...@@ -176,7 +184,7 @@ def test_create_nokia_router_lso_failure( ...@@ -176,7 +184,7 @@ def test_create_nokia_router_lso_failure(
# Run workflow # Run workflow
product_id = get_product_id_by_name(ProductName.ROUTER) product_id = get_product_id_by_name(ProductName.ROUTER)
initial_router_data = [{"product": product_id}, router_creation_input_form_data, {}] initial_router_data = [{"product": product_id}, router_creation_input_form_data | {"router_role": router_role}, {}]
result, process_stat, step_log = run_workflow("create_router", initial_router_data) result, process_stat, step_log = run_workflow("create_router", initial_router_data)
result, step_log = assert_lso_interaction_success(result, process_stat, step_log) result, step_log = assert_lso_interaction_success(result, process_stat, step_log)
......
...@@ -19,7 +19,7 @@ from test.workflows import ( ...@@ -19,7 +19,7 @@ from test.workflows import (
@pytest.mark.workflow() @pytest.mark.workflow()
@patch("gso.services.lso_client._send_request") @patch("gso.services.lso_client._send_request")
@patch("gso.workflows.router.promote_p_to_pe.KentikClient") @patch("gso.utils.workflow_steps.KentikClient")
def test_promote_p_to_pe_success( def test_promote_p_to_pe_success(
mock_kentik_client, mock_kentik_client,
mock_execute_playbook, mock_execute_playbook,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment