This workflow migrates an L2 Core Service to a new Edge Port.
It can be triggered by an operator or automatically by the system during Edge Port migration which is a separate
workflow.
System-triggered migration:
When the system migrates an Edge Port, it runs the workflow automatically. The source and destination Edge Ports are
set to the same values. Then here migration only applies the configuration to the router and fill the drift between
core DB as source of truth and the actual network since the intent of network has changed in the previous workflow
even though the L2 Circuit Service is not changed.
Operator-triggered migration:
When an operator initiates the workflow, they are required to specify both the source and destination EdgePorts.
During the migration process, the system updates the related edge_port reference to replace the source
EdgePort with the destination EdgePort and applies the necessary configuration changes to the router.
Info
Since an L2 Circuit Service has two sides, the workflow must be run separately for each side to fully
migrate the service.
Generate an input form for migrating a Layer 2 Circuit.
Source code in gso/workflows/l2_circuit/migrate_layer_2_circuit.py
| def input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
"""Generate an input form for migrating a Layer 2 Circuit."""
subscription = Layer2Circuit.from_subscription(subscription_id)
def circuit_side_selector() -> TypeAlias:
sides_dict = {
str(side.sbp.edge_port.owner_subscription_id): EdgePort.from_subscription(
side.sbp.edge_port.owner_subscription_id
).description
for side in subscription.layer_2_circuit.layer_2_circuit_sides
}
return cast(
type[Choice],
Choice.__call__("Select one side of the circuit", zip(sides_dict.keys(), sides_dict.items(), strict=True)),
)
class MigrateL2CircuitForm(FormPage):
model_config = ConfigDict(title="Migrating Layer 2 Circuit")
tt_number: TTNumber
replace_side: circuit_side_selector() # type: ignore[valid-type]
divider: Divider = Field(None, exclude=True)
label_a: Label = Field("Are we migrating to a different site?", exclude=True)
migrate_to_different_site: bool = False
label_b: Label = Field("Execute Ansible playbooks on the OLD side of the circuit?", exclude=True)
run_old_side_ansible: bool = True
label_c: Label = Field("Execute Ansible playbooks on the NEW side of the circuit?", exclude=True)
run_new_side_ansible: bool = True
initial_user_input = yield MigrateL2CircuitForm
replace_side_partner = get_partner_by_id(EdgePort.from_subscription(initial_user_input.replace_side).customer_id)
class SelectNewEdgePortForm(SubmitFormPage):
model_config = ConfigDict(title="Migrating Layer 2 Circuit")
new_edge_port: active_edge_port_selector(partner_id=replace_side_partner.partner_id) # type: ignore[valid-type]
generate_new_vc_id: bool = False
user_input = yield SelectNewEdgePortForm
return {
"tt_number": initial_user_input.tt_number,
"run_old_side_ansible": initial_user_input.run_old_side_ansible,
"run_new_side_ansible": initial_user_input.run_new_side_ansible,
"subscription": subscription,
"subscription_id": subscription_id,
"old_edge_port": initial_user_input.replace_side,
"new_edge_port": user_input.new_edge_port,
"generate_new_vc_id": user_input.generate_new_vc_id,
}
|
update_subscription_model(subscription, old_edge_port, new_edge_port, generate_new_vc_id)
Replace the old Edge Port with the newly selected one in the subscription model.
Source code in gso/workflows/l2_circuit/migrate_layer_2_circuit.py
| @step("Update subscription model")
def update_subscription_model(
subscription: Layer2Circuit,
old_edge_port: UUIDstr,
new_edge_port: UUIDstr,
generate_new_vc_id: bool, # noqa: FBT001
) -> State:
"""Replace the old Edge Port with the newly selected one in the subscription model."""
replace_index = (
0
if str(subscription.layer_2_circuit.layer_2_circuit_sides[0].sbp.edge_port.owner_subscription_id)
== old_edge_port
else 1
)
subscription.layer_2_circuit.layer_2_circuit_sides[replace_index].sbp.edge_port = EdgePort.from_subscription(
new_edge_port
).edge_port
if generate_new_vc_id:
vc_id = generate_unique_vc_id(l2c_type=subscription.layer_2_circuit.layer_2_circuit_type)
if not vc_id:
msg = "Failed to generate unique Virtual Circuit ID."
raise ProcessFailureError(msg)
subscription.layer_2_circuit.virtual_circuit_id = vc_id
return {"subscription": subscription}
|
migrate_layer_2_circuit()
Migrate a Layer 2 Circuit.
Source code in gso/workflows/l2_circuit/migrate_layer_2_circuit.py
| @workflow(
"Migrate Layer 2 Circuit",
initial_input_form=wrap_modify_initial_input_form(input_form_generator),
target=Target.MODIFY,
)
def migrate_layer_2_circuit() -> StepList:
"""Migrate a Layer 2 Circuit."""
run_old_side_ansible = conditional(lambda state: state["run_old_side_ansible"])
run_new_side_ansible = conditional(lambda state: state["run_new_side_ansible"])
return (
begin
>> store_process_subscription(Target.MODIFY)
>> unsync
>> run_old_side_ansible(generate_fqdn_list)
>> run_old_side_ansible(extract_partner_name_from_edge_port)
>> run_old_side_ansible(lso_interaction(terminate_l2circuit_dry))
>> run_old_side_ansible(lso_interaction(terminate_l2circuit_real))
>> update_subscription_model
>> run_new_side_ansible(generate_fqdn_list)
>> run_new_side_ansible(extract_partner_name_from_edge_port)
>> run_new_side_ansible(lso_interaction(provision_l2circuit_dry))
>> run_new_side_ansible(lso_interaction(provision_l2circuit_real))
>> resync
>> done
)
|