Skip to content

Massive redeploy base config

Massive redeploy base config task for routers.

process_one_router(router_id, tt_number)

Celery subtask to start & wait for a single router redeploy.

Returns (router_fqdn, succeeded:bool, message:str).

Source code in gso/tasks/massive_redeploy_base_config.py
@shared_task(ignore_result=False)
def process_one_router(router_id: UUIDstr, tt_number: TTNumber) -> tuple[str, bool, str]:
    """Celery subtask to start & wait for a single router redeploy.

    Returns (router_fqdn, succeeded:bool, message:str).
    """
    router_fqdn = router_id
    succeeded = False
    message = ""
    try:
        router_fqdn = Router.from_subscription(router_id).router.router_fqdn
        pid = start_process(
            "redeploy_base_config",
            user_inputs=[
                {"subscription_id": router_id},
                {"tt_number": tt_number, "is_massive_redeploy": True},
            ],
        )
        proc = wait_for_workflow_to_stop(pid, check_interval=5, max_retries=60)
        if proc is None:
            message = "Timed out waiting for workflow to complete"
        elif proc.last_step == "Done" and proc.last_status == ProcessStatus.COMPLETED:
            succeeded = True
            message = "Done"
        elif proc.last_status == ProcessStatus.ABORTED:
            message = "Workflow was aborted"
        elif proc.last_status == ProcessStatus.FAILED:
            message = proc.failed_reason or "Workflow failed without a reason"
        else:
            message = f"Workflow status: {proc.last_status}, last step: {proc.last_step}"

    except FormValidationError as e:
        message = f"Validation error: {e}"
    except Exception as e:  # noqa: BLE001
        message = f"Unexpected error: {e}, router_fqdn: {router_fqdn}"

    return router_fqdn, succeeded, message

finalize_massive_redeploy(results, callback_route, selected_routers)

Called once after all process_one_router tasks.results is a list of (FQDN, succeeded, message) tuples.

Source code in gso/tasks/massive_redeploy_base_config.py
@shared_task(ignore_result=False)
def finalize_massive_redeploy(
    results: list[tuple[str, bool, str]], callback_route: str, selected_routers: list[UUIDstr]
) -> None:
    """Called once after all process_one_router tasks.`results` is a list of (FQDN, succeeded, message) tuples."""
    successful_wfs = {}
    failed_wfs = {}
    for router_fqdn, ok, msg in results:
        if ok:
            successful_wfs[router_fqdn] = msg
        else:
            failed_wfs[router_fqdn] = msg

    # fire callback
    oss = settings.load_oss_params()
    callback_url = f"{oss.GENERAL.internal_hostname}{callback_route}"
    payload = {"failed_wfs": failed_wfs, "successful_wfs": successful_wfs}

    try:
        response = requests.post(callback_url, json=payload, timeout=30)
        if not response.ok:
            logger.exception(
                "Callback failed",
                extra={
                    "status_code": response.status_code,
                    "response_text": response.text,
                    "callback_url": callback_url,
                    "failed_wfs": failed_wfs,
                    "selected_routers": selected_routers,
                },
            )
    except Exception as e:
        msg = f"Failed to post callback: {e}"
        logger.exception(
            msg,
            extra={
                "callback_url": callback_url,
                "failed_wfs": failed_wfs,
                "selected_routers": selected_routers,
            },
        )

massive_redeploy_base_config_task(selected_routers, tt_number, callback_route)

Kicks off one Celery subtask per router, then runs the final callback.

Source code in gso/tasks/massive_redeploy_base_config.py
@shared_task(ignore_result=False)
def massive_redeploy_base_config_task(
    selected_routers: list[UUIDstr],
    tt_number: TTNumber,
    callback_route: str,
) -> None:
    """Kicks off one Celery subtask per router, then runs the final callback."""
    unique_ids = list(dict.fromkeys(selected_routers))
    header = [process_one_router.s(rid, tt_number) for rid in unique_ids]  # type: ignore[attr-defined]
    chord(header)(finalize_massive_redeploy.s(callback_route, unique_ids))  # type: ignore[attr-defined]