|
| @@ -645,8 +645,9 @@ func gcOrphanedPreviews(ctx context.Context, svc *services, previewConfig domain |
| 645 | | log.Warn().Str("container", c.Name).Str("image", c.Image).Str("domain", orphanDomain). | 645 | | log.Warn().Str("container", c.Name).Str("image", c.Image).Str("domain", orphanDomain). |
| 646 | | Time("created", c.Created).Msg("orphaned preview container detected, cleaning up") | 646 | | Time("created", c.Created).Msg("orphaned preview container detected, cleaning up") |
| 647 | | | 647 | | |
| 648 | - | // Stop container first, then clean up domain resources while container | 648 | + | // Order: stop → remove volumes/route → remove container → remove network. |
| 649 | - | // still exists (so future scans can rediscover it on failure), then remove. | 649 | + | // Network removal must happen after container removal because the runtime |
| | | 650 | + | // refuses to delete a network that still has containers attached. |
| 650 | | if err := svc.runtime.StopContainer(ctx, c.Name); err != nil { | 651 | | if err := svc.runtime.StopContainer(ctx, c.Name); err != nil { |
| 651 | | log.Warn().Err(err).Str("container", c.Name).Msg("failed to stop orphan container") | 652 | | log.Warn().Err(err).Str("container", c.Name).Msg("failed to stop orphan container") |
| 652 | | } | 653 | | } |
|
| @@ -663,20 +664,34 @@ func gcOrphanedPreviews(ctx context.Context, svc *services, previewConfig domain |
| 663 | | log.Warn().Err(err).Str("container", c.Name).Msg("failed to remove orphan container") | 664 | | log.Warn().Err(err).Str("container", c.Name).Msg("failed to remove orphan container") |
| 664 | | } | 665 | | } |
| 665 | | | 666 | | |
| | | 667 | + | // Remove network after container is gone. |
| | | 668 | + | if orphanDomain != "" { |
| | | 669 | + | if err := removeOrphanNetwork(ctx, svc, strings.ReplaceAll(orphanDomain, ".", "-"), log); err != nil { |
| | | 670 | + | log.Warn().Err(err).Str("container", c.Name).Msg("failed to remove orphan network after container removal") |
| | | 671 | + | } |
| | | 672 | + | } |
| | | 673 | + | |
| 666 | | log.Info().Str("container", c.Name).Str("domain", orphanDomain).Msg("orphaned preview container cleaned up") | 674 | | log.Info().Str("container", c.Name).Str("domain", orphanDomain).Msg("orphaned preview container cleaned up") |
| 667 | | } | 675 | | } |
| | | 676 | + | |
| | | 677 | + | // Re-sync container state so stale routes disappear from routes list. |
| | | 678 | + | if len(orphans) > 0 { |
| | | 679 | + | if err := svc.containerSvc.SyncContainers(ctx); err != nil { |
| | | 680 | + | log.Warn().Err(err).Msg("failed to sync containers after orphan GC") |
| | | 681 | + | } |
| | | 682 | + | } |
| 668 | | } | 683 | | } |
| 669 | | | 684 | | |
| 670 | - | // cleanupOrphanDomainResources removes volumes, network, and route for an | 685 | + | // cleanupOrphanDomainResources removes volumes and route for an orphaned |
| 671 | - | // orphaned preview domain. Returns an error if any step fails so the caller | 686 | + | // preview domain. Network removal is handled separately in gcOrphanedPreviews |
| 672 | - | // can defer container removal until the next scan. | 687 | + | // after the container is removed. Returns an error if any step fails so the |
| | | 688 | + | // caller can defer container removal until the next scan. |
| 673 | | func cleanupOrphanDomainResources(ctx context.Context, svc *services, orphanDomain string) error { | 689 | | func cleanupOrphanDomainResources(ctx context.Context, svc *services, orphanDomain string) error { |
| 674 | | log := zerowrap.FromCtx(ctx) | 690 | | log := zerowrap.FromCtx(ctx) |
| 675 | | domainSanitized := strings.ReplaceAll(orphanDomain, ".", "-") | 691 | | domainSanitized := strings.ReplaceAll(orphanDomain, ".", "-") |
| 676 | | var errs []error | 692 | | var errs []error |
| 677 | | | 693 | | |
| 678 | | errs = append(errs, removeOrphanVolumes(ctx, svc, domainSanitized, log)...) | 694 | | errs = append(errs, removeOrphanVolumes(ctx, svc, domainSanitized, log)...) |
| 679 | - | errs = append(errs, removeOrphanNetwork(ctx, svc, domainSanitized, log)) | | | |
| 680 | | errs = append(errs, removeOrphanRoute(ctx, svc, orphanDomain, log)) | 695 | | errs = append(errs, removeOrphanRoute(ctx, svc, orphanDomain, log)) |
| 681 | | svc.proxySvc.InvalidateTarget(ctx, orphanDomain) | 696 | | svc.proxySvc.InvalidateTarget(ctx, orphanDomain) |
| 682 | | | 697 | | |