mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 00:22:14 +01:00
test(integration): prune orphaned networks to avoid subnet exhaustion
This commit is contained in:
2
go.mod
2
go.mod
@@ -16,6 +16,7 @@ require (
|
|||||||
github.com/mholt/archives v0.1.5
|
github.com/mholt/archives v0.1.5
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27
|
github.com/microcosm-cc/bluemonday v1.0.27
|
||||||
github.com/moby/moby/api v1.54.2
|
github.com/moby/moby/api v1.54.2
|
||||||
|
github.com/moby/moby/client v0.4.1
|
||||||
github.com/prometheus/client_golang v1.23.2
|
github.com/prometheus/client_golang v1.23.2
|
||||||
github.com/shirou/gopsutil/v4 v4.26.4
|
github.com/shirou/gopsutil/v4 v4.26.4
|
||||||
github.com/spf13/pflag v1.0.10
|
github.com/spf13/pflag v1.0.10
|
||||||
@@ -90,7 +91,6 @@ require (
|
|||||||
github.com/minio/minlz v1.1.1 // indirect
|
github.com/minio/minlz v1.1.1 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
github.com/moby/go-archive v0.2.0 // indirect
|
github.com/moby/go-archive v0.2.0 // indirect
|
||||||
github.com/moby/moby/client v0.4.1 // indirect
|
|
||||||
github.com/moby/patternmatcher v0.6.1 // indirect
|
github.com/moby/patternmatcher v0.6.1 // indirect
|
||||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||||
github.com/moby/sys/user v0.4.0 // indirect
|
github.com/moby/sys/user v0.4.0 // indirect
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -48,6 +49,14 @@ func TestMain(m *testing.M) {
|
|||||||
// Reset the failure collector before each run.
|
// Reset the failure collector before each run.
|
||||||
scenario.ResetFailedScenarios()
|
scenario.ResetFailedScenarios()
|
||||||
|
|
||||||
|
// Reclaim subnets leaked by prior runs or failed container starts
|
||||||
|
// before they exhaust Docker's predefined address pools.
|
||||||
|
if deleted, err := scenario.PruneOrphanedNetworks(context.Background()); err != nil {
|
||||||
|
fmt.Fprintf(colors.Colored(os.Stdout), "warning: prune orphaned networks: %v\n", err)
|
||||||
|
} else if deleted > 0 {
|
||||||
|
fmt.Fprintf(colors.Colored(os.Stdout), "pruned %d orphaned network(s)\n", deleted)
|
||||||
|
}
|
||||||
|
|
||||||
code := godog.TestSuite{
|
code := godog.TestSuite{
|
||||||
Name: "integration",
|
Name: "integration",
|
||||||
ScenarioInitializer: scenario.InitializeScenario,
|
ScenarioInitializer: scenario.InitializeScenario,
|
||||||
|
|||||||
@@ -8,12 +8,44 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/moby/moby/api/types/container"
|
"github.com/moby/moby/api/types/container"
|
||||||
|
"github.com/moby/moby/client"
|
||||||
"github.com/testcontainers/testcontainers-go"
|
"github.com/testcontainers/testcontainers-go"
|
||||||
"github.com/testcontainers/testcontainers-go/exec"
|
"github.com/testcontainers/testcontainers-go/exec"
|
||||||
"github.com/testcontainers/testcontainers-go/network"
|
"github.com/testcontainers/testcontainers-go/network"
|
||||||
"github.com/testcontainers/testcontainers-go/wait"
|
"github.com/testcontainers/testcontainers-go/wait"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// testcontainersLabel is the label testcontainers-go stamps on every
|
||||||
|
// container and network it creates. Pruning on this label only ever touches
|
||||||
|
// resources owned by the test suite.
|
||||||
|
const testcontainersLabel = "org.testcontainers"
|
||||||
|
|
||||||
|
// PruneOrphanedNetworks removes dangling networks created by the test suite.
|
||||||
|
// Each scenario spins a dedicated network, and a failed container start can
|
||||||
|
// leak one before teardown records it. Leaked networks consume Docker's
|
||||||
|
// predefined address pools until none remain and every later scenario fails
|
||||||
|
// with "all predefined address pools have been fully subnetted". Call this
|
||||||
|
// before a run and between retries to reclaim the subnets.
|
||||||
|
//
|
||||||
|
// Only unused networks bearing the testcontainers label are removed, so
|
||||||
|
// running containers and operator networks are never affected.
|
||||||
|
func PruneOrphanedNetworks(ctx context.Context) (int, error) {
|
||||||
|
cli, err := client.New(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("create Docker client: %w", err)
|
||||||
|
}
|
||||||
|
defer cli.Close()
|
||||||
|
|
||||||
|
filters := client.Filters{}.Add("label", testcontainersLabel+"=true")
|
||||||
|
|
||||||
|
report, err := cli.NetworkPrune(ctx, client.NetworkPruneOptions{Filters: filters})
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("prune networks: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(report.Report.NetworksDeleted), nil
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
GotenbergDockerRepository string
|
GotenbergDockerRepository string
|
||||||
GotenbergVersion string
|
GotenbergVersion string
|
||||||
@@ -101,10 +133,20 @@ func startGotenbergContainer(ctx context.Context, env map[string]string) (*testc
|
|||||||
Logger: &noopLogger{},
|
Logger: &noopLogger{},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// The network is already created. The scenario teardown only
|
||||||
|
// removes networks it knows about, and the caller discards n on
|
||||||
|
// error, so remove it here to avoid leaking a subnet on every
|
||||||
|
// failed start. Leaked networks accumulate until Docker's address
|
||||||
|
// pools are fully subnetted and all later scenarios fail.
|
||||||
|
if errRemove := n.Remove(ctx); errRemove != nil {
|
||||||
|
err = fmt.Errorf("start new Gotenberg container: %w (also failed to remove network: %v)", err, errRemove)
|
||||||
|
} else {
|
||||||
err = fmt.Errorf("start new Gotenberg container: %w", err)
|
err = fmt.Errorf("start new Gotenberg container: %w", err)
|
||||||
}
|
}
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return n, c, err
|
return n, c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func execCommandInIntegrationToolsContainer(ctx context.Context, cmd []string, path string) (string, error) {
|
func execCommandInIntegrationToolsContainer(ctx context.Context, cmd []string, path string) (string, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user