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

Add documentation for GÉANT IP service related code

parent b4fedb4f
Branches
No related tags found
1 merge request!286Add Edge Port, GÉANT IP and IAS products
Showing
with 45 additions and 35 deletions
``gso.workflows.edge_port.terminate_edge_port`` ``gso.workflows.edge_port.terminate_edge_port``
============================================== ===============================================
.. automodule:: gso.workflows.edge_port.terminate_edge_port .. automodule:: gso.workflows.edge_port.terminate_edge_port
:members: :members:
......
...@@ -25,6 +25,7 @@ custom.Contractions = YES ...@@ -25,6 +25,7 @@ custom.Contractions = YES
; Using a "regular" - instead of an en dash is totally fine ; Using a "regular" - instead of an en dash is totally fine
Microsoft.Negative = NO Microsoft.Negative = NO
Microsoft.RangeFormat = NO Microsoft.RangeFormat = NO
Microsoft.We = suggestion
TokenIgnores = (:term:`\S+`), (:param \S+(?: \S+)?:), (:type \S+:), (:return \S+:), (:rtype: \S+), (:class:`\S+`) TokenIgnores = (:term:`\S+`), (:param \S+(?: \S+)?:), (:type \S+:), (:return \S+:), (:rtype: \S+), (:class:`\S+`)
......
...@@ -31,3 +31,7 @@ OPA ...@@ -31,3 +31,7 @@ OPA
OIDC OIDC
HTTPBearer HTTPBearer
Kentik Kentik
UTC
EARL
SURF
[Ee]nsure
...@@ -7,7 +7,6 @@ swap: ...@@ -7,7 +7,6 @@ swap:
can't: cannot can't: cannot
couldn't: could not couldn't: could not
didn't: did not didn't: did not
don't: do not
doesn't: does not doesn't: does not
hasn't: has not hasn't: has not
haven't: have not haven't: have not
......
...@@ -114,7 +114,7 @@ class EdgePortBlock(EdgePortBlockProvisioning, lifecycle=[SubscriptionLifecycle. ...@@ -114,7 +114,7 @@ class EdgePortBlock(EdgePortBlockProvisioning, lifecycle=[SubscriptionLifecycle.
edge_port_enable_lacp: bool edge_port_enable_lacp: bool
#: The type of encapsulation used on this edge port, by default DOT1Q. #: The type of encapsulation used on this edge port, by default DOT1Q.
edge_port_encapsulation: EncapsulationType = EncapsulationType.DOT1Q edge_port_encapsulation: EncapsulationType = EncapsulationType.DOT1Q
#: The MAC address assigned to this edge port, if applicable. #: The :term:`MAC` address assigned to this edge port, if applicable.
edge_port_mac_address: str | None = None edge_port_mac_address: str | None = None
#: The speed capacity of each member in the physical port. #: The speed capacity of each member in the physical port.
edge_port_member_speed: PhysicalPortCapacity edge_port_member_speed: PhysicalPortCapacity
...@@ -126,7 +126,7 @@ class EdgePortBlock(EdgePortBlockProvisioning, lifecycle=[SubscriptionLifecycle. ...@@ -126,7 +126,7 @@ class EdgePortBlock(EdgePortBlockProvisioning, lifecycle=[SubscriptionLifecycle.
edge_port_ignore_if_down: bool = False edge_port_ignore_if_down: bool = False
#: The GEANT GA ID associated with this edge port, if any. #: The GEANT GA ID associated with this edge port, if any.
edge_port_geant_ga_id: str | None = None edge_port_geant_ga_id: str | None = None
#: A list of LAG members associated with this edge port. #: A list of :term:`LAG` members associated with this edge port.
edge_port_ae_members: LAGMemberList[EdgePortAEMemberBlock] # type: ignore[assignment] edge_port_ae_members: LAGMemberList[EdgePortAEMemberBlock] # type: ignore[assignment]
#: A list of Service Binding Ports associated with this Edge Port #: A list of Service Binding Ports associated with this Edge Port
edge_port_sbp_list: list[ServiceBindingPort] # type: ignore[assignment] edge_port_sbp_list: list[ServiceBindingPort] # type: ignore[assignment]
...@@ -21,7 +21,7 @@ class NRENAccessPortProvisioning(NRENAccessPortInactive, lifecycle=[Subscription ...@@ -21,7 +21,7 @@ class NRENAccessPortProvisioning(NRENAccessPortInactive, lifecycle=[Subscription
"""An access port for an R&E :term:`NREN` service that is being provisioned.""" """An access port for an R&E :term:`NREN` service that is being provisioned."""
nren_ap_type: APType nren_ap_type: APType
geant_ip_ep: EdgePortBlockProvisioning # type: ignore[assignment] geant_ip_ep: EdgePortBlockProvisioning
class NRENAccessPort(NRENAccessPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): class NRENAccessPort(NRENAccessPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
...@@ -30,7 +30,7 @@ class NRENAccessPort(NRENAccessPortProvisioning, lifecycle=[SubscriptionLifecycl ...@@ -30,7 +30,7 @@ class NRENAccessPort(NRENAccessPortProvisioning, lifecycle=[SubscriptionLifecycl
#: The type of Access Port #: The type of Access Port
nren_ap_type: APType nren_ap_type: APType
#: The list of Edge Ports where this service terminates. #: The list of Edge Ports where this service terminates.
geant_ip_ep: EdgePortBlock # type: ignore[assignment] geant_ip_ep: EdgePortBlock
class GeantIPBlockInactive( class GeantIPBlockInactive(
......
...@@ -43,9 +43,9 @@ class OpengearBlock(OpengearBlockProvisioning, lifecycle=[SubscriptionLifecycle. ...@@ -43,9 +43,9 @@ class OpengearBlock(OpengearBlockProvisioning, lifecycle=[SubscriptionLifecycle.
opengear_hostname: str opengear_hostname: str
#: The site where the Opengear device is located. #: The site where the Opengear device is located.
opengear_site: SiteBlock opengear_site: SiteBlock
#: The WAN address of the Opengear device. #: The :term:`WAN` address of the Opengear device.
opengear_wan_address: ipaddress.IPv4Address opengear_wan_address: ipaddress.IPv4Address
#: The WAN netmask of the Opengear device. #: The :term:`WAN` netmask of the Opengear device.
opengear_wan_netmask: ipaddress.IPv4Address opengear_wan_netmask: ipaddress.IPv4Address
#: The WAN gateway of the Opengear device. #: The :term:`WAN` gateway of the Opengear device.
opengear_wan_gateway: ipaddress.IPv4Address opengear_wan_gateway: ipaddress.IPv4Address
...@@ -99,6 +99,8 @@ class KentikClient: ...@@ -99,6 +99,8 @@ class KentikClient:
If the site is not found, return an empty dict. If the site is not found, return an empty dict.
.. vale off
:param str site_slug: The name of the site, should be a three-letter slug like COR or POZ. :param str site_slug: The name of the site, should be a three-letter slug like COR or POZ.
""" """
sites = self.get_sites() sites = self.get_sites()
......
...@@ -295,7 +295,7 @@ class NetboxClient: ...@@ -295,7 +295,7 @@ class NetboxClient:
router_name = Router.from_subscription(router_id).router.router_fqdn router_name = Router.from_subscription(router_id).router.router_fqdn
device = self.get_device_by_name(router_name) device = self.get_device_by_name(router_name)
# Get the existing LAG interfaces for the device # Get the existing :term:`LAG` interfaces for the device
lag_interface_names = [ lag_interface_names = [
interface["name"] for interface in self.netbox.dcim.interfaces.filter(device=device.name, type="lag") interface["name"] for interface in self.netbox.dcim.interfaces.filter(device=device.name, type="lag")
] ]
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
"create_site": "Create Site", "create_site": "Create Site",
"create_switch": "Create Switch", "create_switch": "Create Switch",
"create_edge_port": "Create Edge Port", "create_edge_port": "Create Edge Port",
"create_geant_ip": "Create GÉANT IP",
"deploy_twamp": "Deploy TWAMP", "deploy_twamp": "Deploy TWAMP",
"migrate_iptrunk": "Migrate IP Trunk", "migrate_iptrunk": "Migrate IP Trunk",
"modify_isis_metric": "Modify the ISIS metric", "modify_isis_metric": "Modify the ISIS metric",
......
...@@ -209,15 +209,18 @@ def active_edge_port_selector(*, geant_only: bool | None = None) -> Choice: ...@@ -209,15 +209,18 @@ def active_edge_port_selector(*, geant_only: bool | None = None) -> Choice:
if geant_only is not None: if geant_only is not None:
# ``geant_only`` is set, so we will filter accordingly. # ``geant_only`` is set, so we will filter accordingly.
geant_partner_id = get_partner_by_name("GEANT")["partner_id"] geant_partner_id = get_partner_by_name("GEANT")["partner_id"]
edge_port_subscriptions = filter( edge_port_subscriptions = list(
lambda subscription: geant_only ^ bool(subscription["customer_id"] != geant_partner_id), filter(
edge_port_subscriptions, lambda subscription: geant_only ^ bool(subscription["customer_id"] != geant_partner_id),
edge_port_subscriptions,
)
) )
edge_port_subscriptions = {str(port["subscription_id"]): port["description"] for port in edge_port_subscriptions} edge_ports = {str(port["subscription_id"]): port["description"] for port in edge_port_subscriptions}
return Choice( return Choice(
"Select an Edge Port", zip(edge_port_subscriptions.keys(), edge_port_subscriptions.items(), strict=True) "Select an Edge Port",
zip(edge_ports.keys(), edge_ports.items(), strict=True), # type: ignore[arg-type]
) )
...@@ -229,11 +232,11 @@ def partner_choice() -> Choice: ...@@ -229,11 +232,11 @@ def partner_choice() -> Choice:
def validate_edge_port_number_of_members_based_on_lacp(*, number_of_members: int, enable_lacp: bool) -> None: def validate_edge_port_number_of_members_based_on_lacp(*, number_of_members: int, enable_lacp: bool) -> None:
"""Validate the number of edge port members based on the LACP setting. """Validate the number of edge port members based on the :term:`LACP` setting.
:param number_of_members: The number of members to validate. :param number_of_members: The number of members to validate.
:param enable_lacp: Whether LACP is enabled or not. :param enable_lacp: Whether :term:`LACP` is enabled or not.
:raises ValueError: If the number of members is greater than 1 and LACP is disabled. :raises ValueError: If the number of members is greater than 1 and :term:`LACP` is disabled.
""" """
if number_of_members > 1 and not enable_lacp: if number_of_members > 1 and not enable_lacp:
err_msg = "Number of members must be 1 if LACP is disabled." err_msg = "Number of members must be 1 if LACP is disabled."
......
...@@ -239,7 +239,7 @@ def create_edge_port() -> StepList: ...@@ -239,7 +239,7 @@ def create_edge_port() -> StepList:
* Create and initialise the subscription object in the service database * Create and initialise the subscription object in the service database
* Deploy configuration on the new edge port, first as a dry run * Deploy configuration on the new edge port, first as a dry run
* allocate LAG and LAG members in the Netbox. * allocate :term:`LAG` and :term:`LAG` members in the Netbox.
""" """
return ( return (
begin begin
......
...@@ -70,7 +70,7 @@ def remove_edge_port_real( ...@@ -70,7 +70,7 @@ def remove_edge_port_real(
@step("Netbox Clean Up") @step("Netbox Clean Up")
def netbox_clean_up(subscription: EdgePort) -> None: def netbox_clean_up(subscription: EdgePort) -> None:
"""Update Netbox to remove the edge port LAG interface and all the LAG members.""" """Update Netbox to remove the edge port :term:`LAG` interface and all the :term:`LAG` members."""
nbclient = NetboxClient() nbclient = NetboxClient()
for member in subscription.edge_port.edge_port_ae_members: for member in subscription.edge_port.edge_port_ae_members:
......
...@@ -36,15 +36,15 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: ...@@ -36,15 +36,15 @@ def initial_input_form_generator(product_name: str) -> FormGenerator:
model_config = ConfigDict(title=f"{product_name} - Select partner") model_config = ConfigDict(title=f"{product_name} - Select partner")
tt_number: TTNumber tt_number: TTNumber
partner: partner_choice() partner: partner_choice() # type: ignore[valid-type]
initial_user_input = yield CreateGeantIPForm initial_user_input = yield CreateGeantIPForm
class EdgePortSelection(BaseModel): class EdgePortSelection(BaseModel):
edge_port: active_edge_port_selector() edge_port: active_edge_port_selector() # type: ignore[valid-type]
ap_type: APType ap_type: APType
def __hash__(self): def __hash__(self) -> int:
return self.edge_port.__hash__() return self.edge_port.__hash__()
class EdgePortSelectionForm(FormPage): class EdgePortSelectionForm(FormPage):
......
...@@ -255,7 +255,7 @@ def dig_all_hosts_v6(new_ipv6_network: str) -> None: ...@@ -255,7 +255,7 @@ def dig_all_hosts_v6(new_ipv6_network: str) -> None:
@step("Ping all hosts in the assigned IPv4 network") @step("Ping all hosts in the assigned IPv4 network")
def ping_all_hosts_v4(new_ipv4_network: str) -> None: def ping_all_hosts_v4(new_ipv4_network: str) -> None:
"""Ping all hosts in the IPv4 network to verify they're not in use.""" """Ping all hosts in the IPv4 network to verify they are not in use."""
unavailable_hosts = [host for host in IPv4Network(new_ipv4_network) if ping(str(host), timeout=1)] unavailable_hosts = [host for host in IPv4Network(new_ipv4_network) if ping(str(host), timeout=1)]
if unavailable_hosts: if unavailable_hosts:
...@@ -265,7 +265,7 @@ def ping_all_hosts_v4(new_ipv4_network: str) -> None: ...@@ -265,7 +265,7 @@ def ping_all_hosts_v4(new_ipv4_network: str) -> None:
@step("Ping all hosts in the assigned IPv6 network") @step("Ping all hosts in the assigned IPv6 network")
def ping_all_hosts_v6(new_ipv6_network: str) -> State: def ping_all_hosts_v6(new_ipv6_network: str) -> State:
"""Ping all hosts in the IPv6 network to verify they're not in use.""" """Ping all hosts in the IPv6 network to verify they are not in use."""
unavailable_hosts = [host for host in IPv6Network(new_ipv6_network) if ping(str(host), timeout=1)] unavailable_hosts = [host for host in IPv6Network(new_ipv6_network) if ping(str(host), timeout=1)]
if unavailable_hosts: if unavailable_hosts:
......
...@@ -89,7 +89,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ...@@ -89,7 +89,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
): ):
# We want to stay on the same site, so all routers that are in different sites get skipped. # We want to stay on the same site, so all routers that are in different sites get skipped.
continue continue
# If migrate_to_different_site is true, we can add ALL routers to the result map # If migrate_to_different_site is true, we can add *all* routers to the result map
routers[str(router_id)] = router["description"] routers[str(router_id)] = router["description"]
new_router_enum = Choice("Select a new router", zip(routers.keys(), routers.items(), strict=True)) # type: ignore[arg-type] new_router_enum = Choice("Select a new router", zip(routers.keys(), routers.items(), strict=True)) # type: ignore[arg-type]
...@@ -204,7 +204,7 @@ def calculate_old_side_data(subscription: Iptrunk, replace_index: int) -> State: ...@@ -204,7 +204,7 @@ def calculate_old_side_data(subscription: Iptrunk, replace_index: int) -> State:
@step("Check Optical PRE levels on the trunk endpoint") @step("Check Optical PRE levels on the trunk endpoint")
def check_ip_trunk_optical_levels_pre(subscription: Iptrunk) -> LSOState: def check_ip_trunk_optical_levels_pre(subscription: Iptrunk) -> LSOState:
"""Check Optical PRE levels on the trunk.""" """Check Optical levels on the trunk before migration."""
extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "optical_pre"} extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "optical_pre"}
return { return {
...@@ -252,7 +252,7 @@ def check_ip_trunk_optical_levels_post( ...@@ -252,7 +252,7 @@ def check_ip_trunk_optical_levels_post(
def check_ip_trunk_lldp( def check_ip_trunk_lldp(
subscription: Iptrunk, new_node: Router, new_lag_member_interfaces: list[dict], replace_index: int subscription: Iptrunk, new_node: Router, new_lag_member_interfaces: list[dict], replace_index: int
) -> LSOState: ) -> LSOState:
"""Check LLDP on the new trunk endpoints.""" """Check :term:`LLDP` on the new trunk endpoints."""
extra_vars = { extra_vars = {
"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "wfo_ip_trunk_json": json.loads(json_dumps(subscription)),
"new_node": json.loads(json_dumps(new_node)), "new_node": json.loads(json_dumps(new_node)),
...@@ -489,7 +489,7 @@ def update_remaining_side_bfd_real( ...@@ -489,7 +489,7 @@ def update_remaining_side_bfd_real(
@step("Check BFD session over trunk") @step("Check BFD session over trunk")
def check_ip_trunk_bfd(subscription: Iptrunk, new_node: Router, replace_index: int) -> LSOState: def check_ip_trunk_bfd(subscription: Iptrunk, new_node: Router, replace_index: int) -> LSOState:
"""Check BFD session across the new trunk.""" """Check :term:`BFD` session across the new trunk."""
extra_vars = { extra_vars = {
"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "wfo_ip_trunk_json": json.loads(json_dumps(subscription)),
"new_node": json.loads(json_dumps(new_node)), "new_node": json.loads(json_dumps(new_node)),
...@@ -830,7 +830,7 @@ def migrate_iptrunk() -> StepList: ...@@ -830,7 +830,7 @@ def migrate_iptrunk() -> StepList:
* Deploy a new :term:`ISIS` interface between routers A and C * Deploy a new :term:`ISIS` interface between routers A and C
* Wait for operator confirmation that :term:`ISIS` is behaving as expected * Wait for operator confirmation that :term:`ISIS` is behaving as expected
* Restore the old :term:`ISIS` metric on the new trunk * Restore the old :term:`ISIS` metric on the new trunk
* Delete the old, disabled configuration on the routers, first as a dry run * Delete the old configuration from the routers, first as a dry run
* Reflect the changes made in :term:`IPAM` * Reflect the changes made in :term:`IPAM`
* Update the subscription model in the database * Update the subscription model in the database
* Update the reserved interfaces in Netbox * Update the reserved interfaces in Netbox
......
...@@ -205,7 +205,7 @@ def check_ip_trunk_connectivity(subscription: Iptrunk) -> LSOState: ...@@ -205,7 +205,7 @@ def check_ip_trunk_connectivity(subscription: Iptrunk) -> LSOState:
@step("Check LLDP on the trunk endpoints") @step("Check LLDP on the trunk endpoints")
def check_ip_trunk_lldp(subscription: Iptrunk) -> LSOState: def check_ip_trunk_lldp(subscription: Iptrunk) -> LSOState:
"""Check LLDP on trunk endpoints.""" """Check :term:`LLDP` on trunk endpoints."""
extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "lldp"} extra_vars = {"wfo_ip_trunk_json": json.loads(json_dumps(subscription)), "check": "lldp"}
return { return {
......
...@@ -210,7 +210,7 @@ def validate_iptrunk() -> StepList: ...@@ -210,7 +210,7 @@ def validate_iptrunk() -> StepList:
* Verify that the :term:`LAG` interfaces are correctly configured in :term:`IPAM`. * Verify that the :term:`LAG` interfaces are correctly configured in :term:`IPAM`.
* Check correct configuration of interfaces in NetBox. * Check correct configuration of interfaces in NetBox.
* Verify the configuration on both sides of the trunk is intact. * Verify the configuration on both sides of the trunk is intact.
* Check the ISIS metric of the trunk. * Check the :term:`ISIS` metric of the trunk.
* Verify that TWAMP configuration is correct. * Verify that TWAMP configuration is correct.
If a trunk has a Juniper router on both sides, it is considered legacy and does not require validation. If a trunk has a Juniper router on both sides, it is considered legacy and does not require validation.
......
...@@ -44,7 +44,7 @@ def initial_input_form_generator(product_name: str) -> FormGenerator: ...@@ -44,7 +44,7 @@ def initial_input_form_generator(product_name: str) -> FormGenerator:
tt_number: TTNumber tt_number: TTNumber
partner: ReadOnlyField("GEANT", default_type=str) # type: ignore[valid-type] partner: ReadOnlyField("GEANT", default_type=str) # type: ignore[valid-type]
vendor: Vendor vendor: Vendor
router_site: active_site_selector() router_site: active_site_selector() # type: ignore[valid-type]
hostname: str hostname: str
ts_port: PortNumber ts_port: PortNumber
router_role: RouterRole router_role: RouterRole
......
...@@ -34,8 +34,8 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator: ...@@ -34,8 +34,8 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
def update_subscription_model(subscription: Router, connection_strategy: str) -> State: def update_subscription_model(subscription: Router, connection_strategy: str) -> State:
"""Update the database model to reflect the new connection strategy. """Update the database model to reflect the new connection strategy.
If the connection strategy is set to IN-BAND, then access_via_ts should be set to False. If the connection strategy is set to in-band, then access_via_ts should be set to False.
Conversely, if the connection strategy is set to OUT-OF-BAND, access_via_ts should be set to True. Conversely, if the connection strategy is set to out-of-band, access_via_ts should be set to True.
""" """
subscription.router.router_access_via_ts = connection_strategy == ConnectionStrategy.OUT_OF_BAND subscription.router.router_access_via_ts = connection_strategy == ConnectionStrategy.OUT_OF_BAND
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment