DeleteDeploymentInner deletes a deployment by deprovisioning its runtime instance and resources. Unlike StopDeploymentInner, this deletes all provisioned resources, wiping persistent state. The implementation is idempotent, enabling it to be called from a retryable background job.
(ctx context.Context, depl *database.Deployment)
| 399 | // Unlike StopDeploymentInner, this deletes all provisioned resources, wiping persistent state. |
| 400 | // The implementation is idempotent, enabling it to be called from a retryable background job. |
| 401 | func (s *Service) DeleteDeploymentInner(ctx context.Context, depl *database.Deployment) error { |
| 402 | // If the deployment is running, try to do a graceful delete. |
| 403 | // It may not be running if it was previously stopped/hibernated. |
| 404 | // Best effort is okay here since instance deletion is not really that important when using the Kubernetes provisioner. |
| 405 | if depl.RuntimeHost != "" && depl.RuntimeInstanceID != "" { |
| 406 | rt, err := s.OpenRuntimeClient(depl) |
| 407 | if err != nil { |
| 408 | s.Logger.Info("failed to open runtime client for deployment deletion", zap.String("deployment_id", depl.ID), zap.String("runtime_instance_id", depl.RuntimeInstanceID), zap.Error(err), observability.ZapCtx(ctx)) |
| 409 | } else { |
| 410 | defer rt.Close() |
| 411 | |
| 412 | // Mirrors the checkpointing from StopDeploymentInner. |
| 413 | if depl.Editable { |
| 414 | _, err = rt.GitPush(ctx, &runtimev1.GitPushRequest{ |
| 415 | InstanceId: depl.RuntimeInstanceID, |
| 416 | CommitMessage: "Auto checkpoint", |
| 417 | }) |
| 418 | if err != nil { |
| 419 | s.Logger.Error("failed to checkpoint repo changes", zap.String("deployment_id", depl.ID), zap.String("runtime_instance_id", depl.RuntimeInstanceID), zap.Error(err), observability.ZapCtx(ctx)) |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | // Graceful instance deletion. |
| 424 | // (In practice, with the Kubernetes provisioner where we anyway delete the disk, this isn't that important.) |
| 425 | _, err = rt.DeleteInstance(ctx, &runtimev1.DeleteInstanceRequest{ |
| 426 | InstanceId: depl.RuntimeInstanceID, |
| 427 | }) |
| 428 | if err != nil { |
| 429 | s.Logger.Error("failed to delete instance", zap.String("deployment_id", depl.ID), zap.String("runtime_instance_id", depl.RuntimeInstanceID), zap.Error(err), observability.ZapCtx(ctx)) |
| 430 | } |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | // Deprovision and delete all provisioned resources for the deployment. |
| 435 | prs, err := s.DB.FindProvisionerResourcesForDeployment(ctx, depl.ID) |
| 436 | if err != nil { |
| 437 | return err |
| 438 | } |
| 439 | for _, pr := range prs { |
| 440 | p, ok := s.ProvisionerSet[pr.Provisioner] |
| 441 | if !ok { |
| 442 | s.Logger.Warn("provisioner: deprovisioning skipped, provisioner not found", zap.String("deployment_id", depl.ID), zap.String("provisioner", pr.Provisioner), zap.String("provision_id", pr.ID), observability.ZapCtx(ctx)) |
| 443 | } else { |
| 444 | err = p.Deprovision(ctx, &provisioner.Resource{ |
| 445 | ID: pr.ID, |
| 446 | Type: provisioner.ResourceType(pr.Type), |
| 447 | State: pr.State, |
| 448 | Config: pr.Config, |
| 449 | }) |
| 450 | if err != nil { |
| 451 | return err |
| 452 | } |
| 453 | } |
| 454 | |
| 455 | err = s.DB.DeleteProvisionerResource(ctx, pr.ID) |
| 456 | if err != nil { |
| 457 | return err |
| 458 | } |
no test coverage detected