From 4902c76cb7fee5d58e734856c1b119a5872a9271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 28 Aug 2024 18:23:09 +0200 Subject: [PATCH 01/22] feat: calculate hash of a container request --- container.go | 10 ++++---- go.mod | 1 + go.sum | 2 ++ hash_test.go | 49 ++++++++++++++++++++++++++++++++++++++ internal/core/hash.go | 17 +++++++++++++ internal/core/hash_test.go | 40 +++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 hash_test.go create mode 100644 internal/core/hash.go create mode 100644 internal/core/hash_test.go diff --git a/container.go b/container.go index 8747335a28..262b75d2c7 100644 --- a/container.go +++ b/container.go @@ -101,7 +101,7 @@ type FromDockerfile struct { // BuildOptionsModifier Modifier for the build options before image build. Use it for // advanced configurations while building the image. Please consider that the modifier // is called after the default build options are set. - BuildOptionsModifier func(*types.ImageBuildOptions) + BuildOptionsModifier func(*types.ImageBuildOptions) `hash:"ignore"` } type ContainerFile struct { @@ -160,10 +160,10 @@ type ContainerRequest struct { ShmSize int64 // Amount of memory shared with the host (in bytes) CapAdd []string // Deprecated: Use HostConfigModifier instead. Add Linux capabilities CapDrop []string // Deprecated: Use HostConfigModifier instead. Drop Linux capabilities - ConfigModifier func(*container.Config) // Modifier for the config before container creation - HostConfigModifier func(*container.HostConfig) // Modifier for the host config before container creation - EnpointSettingsModifier func(map[string]*network.EndpointSettings) // Modifier for the network settings before container creation - LifecycleHooks []ContainerLifecycleHooks // define hooks to be executed during container lifecycle + ConfigModifier func(*container.Config) `hash:"ignore"` // Modifier for the config before container creation + HostConfigModifier func(*container.HostConfig) `hash:"ignore"` // Modifier for the host config before container creation + EnpointSettingsModifier func(map[string]*network.EndpointSettings) `hash:"ignore"` // Modifier for the network settings before container creation + LifecycleHooks []ContainerLifecycleHooks `hash:"ignore"` // define hooks to be executed during container lifecycle LogConsumerCfg *LogConsumerConfig // define the configuration for the log producer and its log consumers to follow the logs } diff --git a/go.mod b/go.mod index 8e9b20a12a..b660b0d3f0 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/docker/go-connections v0.5.0 github.com/google/uuid v1.6.0 github.com/magiconair/properties v1.8.7 + github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/moby/patternmatcher v0.6.0 github.com/moby/term v0.5.0 github.com/opencontainers/image-spec v1.1.0 diff --git a/go.sum b/go.sum index ef44f5f91c..96788fbe19 100644 --- a/go.sum +++ b/go.sum @@ -65,6 +65,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/hash_test.go b/hash_test.go new file mode 100644 index 0000000000..533cce5f06 --- /dev/null +++ b/hash_test.go @@ -0,0 +1,49 @@ +package testcontainers + +import ( + "context" + "testing" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/stretchr/testify/require" + + "github.com/testcontainers/testcontainers-go/internal/core" + "github.com/testcontainers/testcontainers-go/wait" +) + +func TestHashContainerRequest(t *testing.T) { + req := ContainerRequest{ + Image: "nginx", + Env: map[string]string{"a": "b"}, + FromDockerfile: FromDockerfile{ + BuildOptionsModifier: func(options *types.ImageBuildOptions) {}, + }, + ExposedPorts: []string{"80/tcp"}, + Privileged: false, + ImageSubstitutors: []ImageSubstitutor{newPrependHubRegistry("localhost:5000")}, + LifecycleHooks: []ContainerLifecycleHooks{ + { + PreStarts: []ContainerHook{ + func(ctx context.Context, c Container) error { + return nil + }, + }, + }, + }, + HostConfigModifier: func(hostConfig *container.HostConfig) { + // NOOP + }, + WaitingFor: wait.ForLog("nginx: ready"), + } + + hash1, err := core.Hash(req) + require.NoError(t, err) + require.NotEqual(t, 0, hash1) + + hash2, err := core.Hash(req) + require.NoError(t, err) + require.NotEqual(t, 0, hash2) + + require.Equal(t, hash1, hash2) +} diff --git a/internal/core/hash.go b/internal/core/hash.go new file mode 100644 index 0000000000..6c6042afcd --- /dev/null +++ b/internal/core/hash.go @@ -0,0 +1,17 @@ +package core + +import ( + "fmt" + + "github.com/mitchellh/hashstructure/v2" +) + +// Hash calculates a hash of a struct by hashing all of its fields. +func Hash(v interface{}) (uint64, error) { + hash, err := hashstructure.Hash(v, hashstructure.FormatV2, nil) + if err != nil { + return 0, fmt.Errorf("hashing struct: %w", err) + } + + return hash, nil +} diff --git a/internal/core/hash_test.go b/internal/core/hash_test.go new file mode 100644 index 0000000000..abba7461bf --- /dev/null +++ b/internal/core/hash_test.go @@ -0,0 +1,40 @@ +package core_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go/internal/core" +) + +type ExampleTag struct { + Name string + Age int + Score float64 + Valid bool + Fn func() error `hash:"ignore"` +} + +type ExampleNoTag struct { + Name string + Age int + Score float64 + Valid bool + Fn func() error +} + +func TestHashStruct_withTag(t *testing.T) { + e := ExampleTag{"Alice", 30, 95.5, true, nil} + + hash, err := core.Hash(e) + require.NoError(t, err) + require.NotEqual(t, 0, hash) +} + +func TestHashStruct_withNoTag(t *testing.T) { + e := ExampleNoTag{"Alice", 30, 95.5, true, nil} + + hash, err := core.Hash(e) + require.Error(t, err) + require.Equal(t, uint64(0), hash) +} From 10daab5fd6dad19324000eac8d8ba41aa64beec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 29 Aug 2024 11:03:23 +0200 Subject: [PATCH 02/22] chore: run mod tidy --- examples/nginx/go.mod | 1 + examples/nginx/go.sum | 2 ++ examples/toxiproxy/go.mod | 1 + examples/toxiproxy/go.sum | 2 ++ modules/artemis/go.mod | 1 + modules/artemis/go.sum | 2 ++ modules/azurite/go.mod | 1 + modules/azurite/go.sum | 2 ++ modules/cassandra/go.mod | 1 + modules/cassandra/go.sum | 2 ++ modules/chroma/go.mod | 1 + modules/chroma/go.sum | 2 ++ modules/clickhouse/go.mod | 1 + modules/clickhouse/go.sum | 2 ++ modules/cockroachdb/go.mod | 1 + modules/cockroachdb/go.sum | 2 ++ modules/compose/go.mod | 1 + modules/compose/go.sum | 2 ++ modules/consul/go.mod | 1 + modules/consul/go.sum | 2 ++ modules/couchbase/go.mod | 3 +-- modules/couchbase/go.sum | 2 ++ modules/dolt/go.mod | 1 + modules/dolt/go.sum | 2 ++ modules/elasticsearch/go.mod | 1 + modules/elasticsearch/go.sum | 2 ++ modules/gcloud/go.mod | 1 + modules/gcloud/go.sum | 2 ++ modules/grafana-lgtm/go.mod | 1 + modules/grafana-lgtm/go.sum | 2 ++ modules/inbucket/go.mod | 1 + modules/inbucket/go.sum | 2 ++ modules/influxdb/go.mod | 1 + modules/influxdb/go.sum | 2 ++ modules/k3s/go.mod | 1 + modules/k3s/go.sum | 2 ++ modules/k6/go.mod | 1 + modules/k6/go.sum | 2 ++ modules/kafka/go.mod | 1 + modules/kafka/go.sum | 2 ++ modules/localstack/go.mod | 1 + modules/localstack/go.sum | 2 ++ modules/mariadb/go.mod | 1 + modules/mariadb/go.sum | 2 ++ modules/milvus/go.mod | 1 + modules/milvus/go.sum | 2 ++ modules/minio/go.mod | 1 + modules/minio/go.sum | 2 ++ modules/mockserver/go.mod | 1 + modules/mockserver/go.sum | 2 ++ modules/mongodb/go.mod | 1 + modules/mongodb/go.sum | 2 ++ modules/mssql/go.mod | 1 + modules/mssql/go.sum | 2 ++ modules/mysql/go.mod | 1 + modules/mysql/go.sum | 2 ++ modules/nats/go.mod | 1 + modules/nats/go.sum | 2 ++ modules/neo4j/go.mod | 1 + modules/neo4j/go.sum | 2 ++ modules/ollama/go.mod | 1 + modules/ollama/go.sum | 2 ++ modules/openfga/go.mod | 1 + modules/openfga/go.sum | 2 ++ modules/openldap/go.mod | 1 + modules/openldap/go.sum | 2 ++ modules/opensearch/go.mod | 1 + modules/opensearch/go.sum | 2 ++ modules/postgres/go.mod | 1 + modules/postgres/go.sum | 2 ++ modules/pulsar/go.mod | 1 + modules/pulsar/go.sum | 2 ++ modules/qdrant/go.mod | 1 + modules/qdrant/go.sum | 2 ++ modules/rabbitmq/go.mod | 1 + modules/rabbitmq/go.sum | 2 ++ modules/redis/go.mod | 1 + modules/redis/go.sum | 2 ++ modules/redpanda/go.mod | 1 + modules/redpanda/go.sum | 2 ++ modules/registry/go.mod | 1 + modules/registry/go.sum | 2 ++ modules/surrealdb/go.mod | 1 + modules/surrealdb/go.sum | 2 ++ modules/valkey/go.mod | 1 + modules/valkey/go.sum | 2 ++ modules/vault/go.mod | 1 + modules/vault/go.sum | 2 ++ modules/vearch/go.mod | 1 + modules/vearch/go.sum | 2 ++ modules/weaviate/go.mod | 1 + modules/weaviate/go.sum | 2 ++ 92 files changed, 138 insertions(+), 2 deletions(-) diff --git a/examples/nginx/go.mod b/examples/nginx/go.mod index a6f67e793c..2555ba376e 100644 --- a/examples/nginx/go.mod +++ b/examples/nginx/go.mod @@ -28,6 +28,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/examples/nginx/go.sum b/examples/nginx/go.sum index 85338720c8..f3d0972108 100644 --- a/examples/nginx/go.sum +++ b/examples/nginx/go.sum @@ -56,6 +56,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/examples/toxiproxy/go.mod b/examples/toxiproxy/go.mod index 04be7036c1..a3a0d026a1 100644 --- a/examples/toxiproxy/go.mod +++ b/examples/toxiproxy/go.mod @@ -32,6 +32,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/examples/toxiproxy/go.sum b/examples/toxiproxy/go.sum index c62c0ac532..d8dc6977ca 100644 --- a/examples/toxiproxy/go.sum +++ b/examples/toxiproxy/go.sum @@ -66,6 +66,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/artemis/go.mod b/modules/artemis/go.mod index adb9dddf08..06c5a20c87 100644 --- a/modules/artemis/go.mod +++ b/modules/artemis/go.mod @@ -31,6 +31,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/artemis/go.sum b/modules/artemis/go.sum index 69f6d52997..126fb0b71a 100644 --- a/modules/artemis/go.sum +++ b/modules/artemis/go.sum @@ -66,6 +66,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/azurite/go.mod b/modules/azurite/go.mod index 826a457a9a..62d28225c4 100644 --- a/modules/azurite/go.mod +++ b/modules/azurite/go.mod @@ -33,6 +33,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/azurite/go.sum b/modules/azurite/go.sum index 90f8568088..23cd93c8b3 100644 --- a/modules/azurite/go.sum +++ b/modules/azurite/go.sum @@ -79,6 +79,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/cassandra/go.mod b/modules/cassandra/go.mod index fce3c2d919..cc77a87215 100644 --- a/modules/cassandra/go.mod +++ b/modules/cassandra/go.mod @@ -33,6 +33,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/cassandra/go.sum b/modules/cassandra/go.sum index 775e48ecf5..5f20b947d7 100644 --- a/modules/cassandra/go.sum +++ b/modules/cassandra/go.sum @@ -72,6 +72,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/chroma/go.mod b/modules/chroma/go.mod index 2c03baa164..ac92daa60e 100644 --- a/modules/chroma/go.mod +++ b/modules/chroma/go.mod @@ -33,6 +33,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/chroma/go.sum b/modules/chroma/go.sum index e7d70f0539..26f705fe27 100644 --- a/modules/chroma/go.sum +++ b/modules/chroma/go.sum @@ -65,6 +65,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/clickhouse/go.mod b/modules/clickhouse/go.mod index 5542929f72..87a8a178fb 100644 --- a/modules/clickhouse/go.mod +++ b/modules/clickhouse/go.mod @@ -35,6 +35,7 @@ require ( github.com/klauspost/compress v1.17.7 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/clickhouse/go.sum b/modules/clickhouse/go.sum index 2f09c4daae..705a601c35 100644 --- a/modules/clickhouse/go.sum +++ b/modules/clickhouse/go.sum @@ -77,6 +77,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/cockroachdb/go.mod b/modules/cockroachdb/go.mod index d31c6f54ec..7b13d783ae 100644 --- a/modules/cockroachdb/go.mod +++ b/modules/cockroachdb/go.mod @@ -11,6 +11,7 @@ require ( require ( github.com/containerd/platforms v0.2.1 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect golang.org/x/net v0.26.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect diff --git a/modules/cockroachdb/go.sum b/modules/cockroachdb/go.sum index c051f94433..a6343ff2c1 100644 --- a/modules/cockroachdb/go.sum +++ b/modules/cockroachdb/go.sum @@ -71,6 +71,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mdelapenya/tlscert v0.1.0 h1:YTpF579PYUX475eOL+6zyEO3ngLTOUWck78NBuJVXaM= github.com/mdelapenya/tlscert v0.1.0/go.mod h1:wrbyM/DwbFCeCeqdPX/8c6hNOqQgbf0rUDErE1uD+64= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/compose/go.mod b/modules/compose/go.mod index 487bdcb7d0..9ddd84de26 100644 --- a/modules/compose/go.mod +++ b/modules/compose/go.mod @@ -105,6 +105,7 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/miekg/pkcs11 v1.1.1 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/buildkit v0.14.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect diff --git a/modules/compose/go.sum b/modules/compose/go.sum index c05580192e..010429ff57 100644 --- a/modules/compose/go.sum +++ b/modules/compose/go.sum @@ -321,6 +321,8 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyex github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= diff --git a/modules/consul/go.mod b/modules/consul/go.mod index 079447aa27..e450d0cac4 100644 --- a/modules/consul/go.mod +++ b/modules/consul/go.mod @@ -44,6 +44,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect diff --git a/modules/consul/go.sum b/modules/consul/go.sum index d82d1cb435..7227bbb521 100644 --- a/modules/consul/go.sum +++ b/modules/consul/go.sum @@ -173,6 +173,8 @@ github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJys github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod index 96365d44e7..d59c35bd43 100644 --- a/modules/couchbase/go.mod +++ b/modules/couchbase/go.mod @@ -2,8 +2,6 @@ module github.com/testcontainers/testcontainers-go/modules/couchbase go 1.22 -toolchain go1.21.7 - require ( github.com/cenkalti/backoff/v4 v4.2.1 github.com/couchbase/gocb/v2 v2.7.2 @@ -38,6 +36,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/couchbase/go.sum b/modules/couchbase/go.sum index 737e1e5236..f57eb6f0d9 100644 --- a/modules/couchbase/go.sum +++ b/modules/couchbase/go.sum @@ -97,6 +97,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/dolt/go.mod b/modules/dolt/go.mod index 804efb8483..d80796b959 100644 --- a/modules/dolt/go.mod +++ b/modules/dolt/go.mod @@ -29,6 +29,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/dolt/go.sum b/modules/dolt/go.sum index 7784d0b833..58a977fe05 100644 --- a/modules/dolt/go.sum +++ b/modules/dolt/go.sum @@ -58,6 +58,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/elasticsearch/go.mod b/modules/elasticsearch/go.mod index a766e55dd0..4bbcd8298e 100644 --- a/modules/elasticsearch/go.mod +++ b/modules/elasticsearch/go.mod @@ -34,6 +34,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/elasticsearch/go.sum b/modules/elasticsearch/go.sum index 59647a3793..7e35f43aca 100644 --- a/modules/elasticsearch/go.sum +++ b/modules/elasticsearch/go.sum @@ -65,6 +65,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/gcloud/go.mod b/modules/gcloud/go.mod index 00a723f58c..9103262292 100644 --- a/modules/gcloud/go.mod +++ b/modules/gcloud/go.mod @@ -56,6 +56,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/gcloud/go.sum b/modules/gcloud/go.sum index 31d286e7d0..8def4336fd 100644 --- a/modules/gcloud/go.sum +++ b/modules/gcloud/go.sum @@ -150,6 +150,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/grafana-lgtm/go.mod b/modules/grafana-lgtm/go.mod index 73a94c714b..9e5ce182eb 100644 --- a/modules/grafana-lgtm/go.mod +++ b/modules/grafana-lgtm/go.mod @@ -44,6 +44,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/grafana-lgtm/go.sum b/modules/grafana-lgtm/go.sum index 9eb14f31cb..bb8deafc7c 100644 --- a/modules/grafana-lgtm/go.sum +++ b/modules/grafana-lgtm/go.sum @@ -60,6 +60,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/inbucket/go.mod b/modules/inbucket/go.mod index 18939bc445..4f1ffa8258 100644 --- a/modules/inbucket/go.mod +++ b/modules/inbucket/go.mod @@ -33,6 +33,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/inbucket/go.sum b/modules/inbucket/go.sum index 2e403c06ad..3ede71f5f8 100644 --- a/modules/inbucket/go.sum +++ b/modules/inbucket/go.sum @@ -65,6 +65,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/influxdb/go.mod b/modules/influxdb/go.mod index f11c1de449..dbce3f0dec 100644 --- a/modules/influxdb/go.mod +++ b/modules/influxdb/go.mod @@ -32,6 +32,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/influxdb/go.sum b/modules/influxdb/go.sum index ad81df94f6..8c198f237d 100644 --- a/modules/influxdb/go.sum +++ b/modules/influxdb/go.sum @@ -63,6 +63,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/k3s/go.mod b/modules/k3s/go.mod index da3a23fd92..a95150bc56 100644 --- a/modules/k3s/go.mod +++ b/modules/k3s/go.mod @@ -44,6 +44,7 @@ require ( github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/k3s/go.sum b/modules/k3s/go.sum index e08a07dd42..08f1b7d95c 100644 --- a/modules/k3s/go.sum +++ b/modules/k3s/go.sum @@ -95,6 +95,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/k6/go.mod b/modules/k6/go.mod index 58f96d04aa..682988682b 100644 --- a/modules/k6/go.mod +++ b/modules/k6/go.mod @@ -28,6 +28,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/k6/go.sum b/modules/k6/go.sum index 85338720c8..f3d0972108 100644 --- a/modules/k6/go.sum +++ b/modules/k6/go.sum @@ -56,6 +56,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/kafka/go.mod b/modules/kafka/go.mod index 1148bd00f8..3bb20ddf26 100644 --- a/modules/kafka/go.mod +++ b/modules/kafka/go.mod @@ -43,6 +43,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/kafka/go.sum b/modules/kafka/go.sum index 778434567d..ce36d3fd91 100644 --- a/modules/kafka/go.sum +++ b/modules/kafka/go.sum @@ -90,6 +90,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/localstack/go.mod b/modules/localstack/go.mod index 0bd92d1a01..5a15d803fe 100644 --- a/modules/localstack/go.mod +++ b/modules/localstack/go.mod @@ -52,6 +52,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/localstack/go.sum b/modules/localstack/go.sum index 532bf9e05b..afc6b91b8a 100644 --- a/modules/localstack/go.sum +++ b/modules/localstack/go.sum @@ -105,6 +105,8 @@ github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a h1:3Bm7EwfUQUvhNe github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/mariadb/go.mod b/modules/mariadb/go.mod index e8039caf58..59d47925a9 100644 --- a/modules/mariadb/go.mod +++ b/modules/mariadb/go.mod @@ -29,6 +29,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/mariadb/go.sum b/modules/mariadb/go.sum index 7784d0b833..58a977fe05 100644 --- a/modules/mariadb/go.sum +++ b/modules/mariadb/go.sum @@ -58,6 +58,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/milvus/go.mod b/modules/milvus/go.mod index 1b60fe8cf7..c1b30d749c 100644 --- a/modules/milvus/go.mod +++ b/modules/milvus/go.mod @@ -40,6 +40,7 @@ require ( github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/milvus-io/milvus-proto/go-api/v2 v2.4.0 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/milvus/go.sum b/modules/milvus/go.sum index f8cd7dcf33..4fbf7e4472 100644 --- a/modules/milvus/go.sum +++ b/modules/milvus/go.sum @@ -200,6 +200,8 @@ github.com/milvus-io/milvus-proto/go-api/v2 v2.4.0/go.mod h1:1OIl0v5PQeNxIJhCvY+ github.com/milvus-io/milvus-sdk-go/v2 v2.4.0 h1:llESmiYiaFqRh0CUrZCLH0IWWkk5r8/vz0tkaA0YzQo= github.com/milvus-io/milvus-sdk-go/v2 v2.4.0/go.mod h1:8IKyxVV+kd+RADMuMpo8GXnTDq5ZxrSSWpe9nJieboQ= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= diff --git a/modules/minio/go.mod b/modules/minio/go.mod index c50c958c21..86bcfee61c 100644 --- a/modules/minio/go.mod +++ b/modules/minio/go.mod @@ -34,6 +34,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/minio/go.sum b/modules/minio/go.sum index 55013e4221..3fc7f80b12 100644 --- a/modules/minio/go.sum +++ b/modules/minio/go.sum @@ -70,6 +70,8 @@ github.com/minio/minio-go/v7 v7.0.68 h1:hTqSIfLlpXaKuNy4baAp4Jjy2sqZEN9hRxD0M4aO github.com/minio/minio-go/v7 v7.0.68/go.mod h1:XAvOPJQ5Xlzk5o3o/ArO2NMbhSGkimC+bpW/ngRKDmQ= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/mockserver/go.mod b/modules/mockserver/go.mod index e2ba76d72d..2715399f35 100644 --- a/modules/mockserver/go.mod +++ b/modules/mockserver/go.mod @@ -30,6 +30,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/mockserver/go.sum b/modules/mockserver/go.sum index e752fd0812..8d82bd22ee 100644 --- a/modules/mockserver/go.sum +++ b/modules/mockserver/go.sum @@ -60,6 +60,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/mongodb/go.mod b/modules/mongodb/go.mod index e7e8c724bc..d02753839b 100644 --- a/modules/mongodb/go.mod +++ b/modules/mongodb/go.mod @@ -30,6 +30,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/mongodb/go.sum b/modules/mongodb/go.sum index 0f2d5d5336..cd4c783218 100644 --- a/modules/mongodb/go.sum +++ b/modules/mongodb/go.sum @@ -60,6 +60,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/mssql/go.mod b/modules/mssql/go.mod index 83411fb7aa..9f514dce7d 100644 --- a/modules/mssql/go.mod +++ b/modules/mssql/go.mod @@ -31,6 +31,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/mssql/go.sum b/modules/mssql/go.sum index 4160a61ee2..a3938259d2 100644 --- a/modules/mssql/go.sum +++ b/modules/mssql/go.sum @@ -78,6 +78,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/microsoft/go-mssqldb v1.7.0 h1:sgMPW0HA6Ihd37Yx0MzHyKD726C2kY/8KJsQtXHNaAs= github.com/microsoft/go-mssqldb v1.7.0/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/mysql/go.mod b/modules/mysql/go.mod index f3f00dcb8b..4a79e5adce 100644 --- a/modules/mysql/go.mod +++ b/modules/mysql/go.mod @@ -30,6 +30,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/mysql/go.sum b/modules/mysql/go.sum index 7784d0b833..58a977fe05 100644 --- a/modules/mysql/go.sum +++ b/modules/mysql/go.sum @@ -58,6 +58,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/nats/go.mod b/modules/nats/go.mod index 0a4863c41e..bdc4e44e46 100644 --- a/modules/nats/go.mod +++ b/modules/nats/go.mod @@ -29,6 +29,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/nats/go.sum b/modules/nats/go.sum index 11a786d5d4..bf52c6a17d 100644 --- a/modules/nats/go.sum +++ b/modules/nats/go.sum @@ -56,6 +56,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/neo4j/go.mod b/modules/neo4j/go.mod index 13f310eeb5..986d6c17c4 100644 --- a/modules/neo4j/go.mod +++ b/modules/neo4j/go.mod @@ -29,6 +29,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/neo4j/go.sum b/modules/neo4j/go.sum index 2576f66232..11c0b15769 100644 --- a/modules/neo4j/go.sum +++ b/modules/neo4j/go.sum @@ -56,6 +56,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/ollama/go.mod b/modules/ollama/go.mod index 5e586e858e..2687e32f20 100644 --- a/modules/ollama/go.mod +++ b/modules/ollama/go.mod @@ -30,6 +30,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/ollama/go.sum b/modules/ollama/go.sum index 07f9ef689f..8d19062f58 100644 --- a/modules/ollama/go.sum +++ b/modules/ollama/go.sum @@ -58,6 +58,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/openfga/go.mod b/modules/openfga/go.mod index 388b9c040c..1026293fd9 100644 --- a/modules/openfga/go.mod +++ b/modules/openfga/go.mod @@ -29,6 +29,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/openfga/go.sum b/modules/openfga/go.sum index a2fe09d6b4..15dc48143b 100644 --- a/modules/openfga/go.sum +++ b/modules/openfga/go.sum @@ -58,6 +58,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/openldap/go.mod b/modules/openldap/go.mod index 2f13ed78cc..6402794921 100644 --- a/modules/openldap/go.mod +++ b/modules/openldap/go.mod @@ -31,6 +31,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/openldap/go.sum b/modules/openldap/go.sum index 57de498077..513acfde1f 100644 --- a/modules/openldap/go.sum +++ b/modules/openldap/go.sum @@ -65,6 +65,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/opensearch/go.mod b/modules/opensearch/go.mod index 50146f5964..41293c8e50 100644 --- a/modules/opensearch/go.mod +++ b/modules/opensearch/go.mod @@ -28,6 +28,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/opensearch/go.sum b/modules/opensearch/go.sum index 85338720c8..f3d0972108 100644 --- a/modules/opensearch/go.sum +++ b/modules/opensearch/go.sum @@ -56,6 +56,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/postgres/go.mod b/modules/postgres/go.mod index 4b57997260..3f5e477882 100644 --- a/modules/postgres/go.mod +++ b/modules/postgres/go.mod @@ -37,6 +37,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/postgres/go.sum b/modules/postgres/go.sum index 4293379353..08c3fe773e 100644 --- a/modules/postgres/go.sum +++ b/modules/postgres/go.sum @@ -71,6 +71,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/pulsar/go.mod b/modules/pulsar/go.mod index b9e77f4d58..852d3c3783 100644 --- a/modules/pulsar/go.mod +++ b/modules/pulsar/go.mod @@ -51,6 +51,7 @@ require ( github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/pulsar/go.sum b/modules/pulsar/go.sum index e8aa08578a..c50351dc29 100644 --- a/modules/pulsar/go.sum +++ b/modules/pulsar/go.sum @@ -246,6 +246,8 @@ github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3v github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/qdrant/go.mod b/modules/qdrant/go.mod index 85db7229b3..2df1df54e7 100644 --- a/modules/qdrant/go.mod +++ b/modules/qdrant/go.mod @@ -30,6 +30,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/qdrant/go.sum b/modules/qdrant/go.sum index c4425e8182..c8efb37df1 100644 --- a/modules/qdrant/go.sum +++ b/modules/qdrant/go.sum @@ -56,6 +56,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/rabbitmq/go.mod b/modules/rabbitmq/go.mod index e9d4a267fa..6ef7378faf 100644 --- a/modules/rabbitmq/go.mod +++ b/modules/rabbitmq/go.mod @@ -10,6 +10,7 @@ require ( require ( github.com/containerd/platforms v0.2.1 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect golang.org/x/crypto v0.24.0 // indirect golang.org/x/net v0.26.0 // indirect diff --git a/modules/rabbitmq/go.sum b/modules/rabbitmq/go.sum index f57610f497..eedbc920c1 100644 --- a/modules/rabbitmq/go.sum +++ b/modules/rabbitmq/go.sum @@ -61,6 +61,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mdelapenya/tlscert v0.1.0 h1:YTpF579PYUX475eOL+6zyEO3ngLTOUWck78NBuJVXaM= github.com/mdelapenya/tlscert v0.1.0/go.mod h1:wrbyM/DwbFCeCeqdPX/8c6hNOqQgbf0rUDErE1uD+64= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/redis/go.mod b/modules/redis/go.mod index e76c925c7e..7c3e616366 100644 --- a/modules/redis/go.mod +++ b/modules/redis/go.mod @@ -37,6 +37,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/redis/go.sum b/modules/redis/go.sum index 1698de2ecf..252fcf99b8 100644 --- a/modules/redis/go.sum +++ b/modules/redis/go.sum @@ -69,6 +69,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/redpanda/go.mod b/modules/redpanda/go.mod index 4ce12872ee..e17a9a7f9c 100644 --- a/modules/redpanda/go.mod +++ b/modules/redpanda/go.mod @@ -13,6 +13,7 @@ require ( require ( github.com/containerd/platforms v0.2.1 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect golang.org/x/net v0.26.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect diff --git a/modules/redpanda/go.sum b/modules/redpanda/go.sum index cf26162896..e6afbbbb7b 100644 --- a/modules/redpanda/go.sum +++ b/modules/redpanda/go.sum @@ -63,6 +63,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mdelapenya/tlscert v0.1.0 h1:YTpF579PYUX475eOL+6zyEO3ngLTOUWck78NBuJVXaM= github.com/mdelapenya/tlscert v0.1.0/go.mod h1:wrbyM/DwbFCeCeqdPX/8c6hNOqQgbf0rUDErE1uD+64= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/registry/go.mod b/modules/registry/go.mod index 36e95dfdf0..e312359475 100644 --- a/modules/registry/go.mod +++ b/modules/registry/go.mod @@ -31,6 +31,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/registry/go.sum b/modules/registry/go.sum index 5583e9b0fc..72ed0778b3 100644 --- a/modules/registry/go.sum +++ b/modules/registry/go.sum @@ -61,6 +61,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/surrealdb/go.mod b/modules/surrealdb/go.mod index d3d2d049d6..5b79eaecd8 100644 --- a/modules/surrealdb/go.mod +++ b/modules/surrealdb/go.mod @@ -30,6 +30,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/surrealdb/go.sum b/modules/surrealdb/go.sum index 4a82bd3217..8bdf420c72 100644 --- a/modules/surrealdb/go.sum +++ b/modules/surrealdb/go.sum @@ -58,6 +58,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/valkey/go.mod b/modules/valkey/go.mod index 0c1173f987..a0eaf86668 100644 --- a/modules/valkey/go.mod +++ b/modules/valkey/go.mod @@ -34,6 +34,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/valkey/go.sum b/modules/valkey/go.sum index f92f0dbcc7..f630ec048a 100644 --- a/modules/valkey/go.sum +++ b/modules/valkey/go.sum @@ -60,6 +60,8 @@ github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tA github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/vault/go.mod b/modules/vault/go.mod index 064a23bcce..9c5000de2b 100644 --- a/modules/vault/go.mod +++ b/modules/vault/go.mod @@ -38,6 +38,7 @@ require ( github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/vault/go.sum b/modules/vault/go.sum index 5bed30736e..e365d3a765 100644 --- a/modules/vault/go.sum +++ b/modules/vault/go.sum @@ -81,6 +81,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/vearch/go.mod b/modules/vearch/go.mod index eaad237db7..76a5a537aa 100644 --- a/modules/vearch/go.mod +++ b/modules/vearch/go.mod @@ -26,6 +26,7 @@ require ( github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect diff --git a/modules/vearch/go.sum b/modules/vearch/go.sum index 85338720c8..f3d0972108 100644 --- a/modules/vearch/go.sum +++ b/modules/vearch/go.sum @@ -56,6 +56,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= diff --git a/modules/weaviate/go.mod b/modules/weaviate/go.mod index 6572fb3607..b3c2a1281e 100644 --- a/modules/weaviate/go.mod +++ b/modules/weaviate/go.mod @@ -45,6 +45,7 @@ require ( github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect diff --git a/modules/weaviate/go.sum b/modules/weaviate/go.sum index 4d55fd59af..7f8a07b4b1 100644 --- a/modules/weaviate/go.sum +++ b/modules/weaviate/go.sum @@ -148,6 +148,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= From ed3e1fa72d7eb0c4334f0115cd44a1450b1bbaa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 30 Aug 2024 06:32:34 +0200 Subject: [PATCH 03/22] feat: calculate the hash of a container request, considering the copied files --- hash_test.go | 145 ++++++++++++++++++++++++++++++++++++++++++++++-- request_hash.go | 70 +++++++++++++++++++++++ 2 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 request_hash.go diff --git a/hash_test.go b/hash_test.go index 533cce5f06..e0d2879227 100644 --- a/hash_test.go +++ b/hash_test.go @@ -2,13 +2,14 @@ package testcontainers import ( "context" + "os" + "path/filepath" "testing" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/stretchr/testify/require" - "github.com/testcontainers/testcontainers-go/internal/core" "github.com/testcontainers/testcontainers-go/wait" ) @@ -35,15 +36,151 @@ func TestHashContainerRequest(t *testing.T) { // NOOP }, WaitingFor: wait.ForLog("nginx: ready"), + Files: []ContainerFile{ + { + HostFilePath: filepath.Join("testdata", "hello.sh"), + ContainerFilePath: "/hello.sh", + FileMode: 0755, + }, + }, + } + + hash1 := req.hash() + require.NotEqual(t, 0, hash1) + + hash2 := req.hash() + require.NotEqual(t, 0, hash2) + + require.Equal(t, hash1.Hash, hash2.Hash) + require.Equal(t, hash1.FilesHash, hash2.FilesHash) +} + +func TestHashContainerRequest_differs(t *testing.T) { + req1 := ContainerRequest{ + Image: "nginx", + Env: map[string]string{"a": "b"}, + FromDockerfile: FromDockerfile{ + BuildOptionsModifier: func(options *types.ImageBuildOptions) {}, + }, + ExposedPorts: []string{"80/tcp"}, + Privileged: false, + ImageSubstitutors: []ImageSubstitutor{newPrependHubRegistry("localhost:5000")}, + LifecycleHooks: []ContainerLifecycleHooks{ + { + PreStarts: []ContainerHook{ + func(ctx context.Context, c Container) error { + return nil + }, + }, + }, + }, + HostConfigModifier: func(hostConfig *container.HostConfig) { + // NOOP + }, + WaitingFor: wait.ForLog("nginx: ready"), + Files: []ContainerFile{ + { + HostFilePath: filepath.Join("testdata", "hello.sh"), + ContainerFilePath: "/hello.sh", + FileMode: 0755, + }, + }, } - hash1, err := core.Hash(req) + req2 := ContainerRequest{ + Image: "nginx1", // this is the only difference with req1 + Env: map[string]string{"a": "b"}, + FromDockerfile: FromDockerfile{ + BuildOptionsModifier: func(options *types.ImageBuildOptions) {}, + }, + ExposedPorts: []string{"80/tcp"}, + Privileged: false, + ImageSubstitutors: []ImageSubstitutor{newPrependHubRegistry("localhost:5000")}, + LifecycleHooks: []ContainerLifecycleHooks{ + { + PreStarts: []ContainerHook{ + func(ctx context.Context, c Container) error { + return nil + }, + }, + }, + }, + HostConfigModifier: func(hostConfig *container.HostConfig) { + // NOOP + }, + WaitingFor: wait.ForLog("nginx: ready"), + Files: []ContainerFile{ + { + HostFilePath: filepath.Join("testdata", "hello.sh"), + ContainerFilePath: "/hello.sh", + FileMode: 0755, + }, + }, + } + + hash1 := req1.hash() + require.NotEqual(t, 0, hash1) + + hash2 := req2.hash() + require.NotEqual(t, 0, hash2) + + require.NotEqual(t, hash1.Hash, hash2.Hash) + require.Equal(t, hash1.FilesHash, hash2.FilesHash) +} + +func TestHashContainerRequest_modifiedFiles(t *testing.T) { + tmpDir := t.TempDir() + + // create a temporary file to be used in the test + tmpFile := filepath.Join(tmpDir, "hello.sh") + + f, err := os.Create(tmpFile) + require.NoError(t, err) + + _, err = f.WriteString("echo hello gopher!") require.NoError(t, err) + + req := ContainerRequest{ + Image: "nginx", + Env: map[string]string{"a": "b"}, + FromDockerfile: FromDockerfile{ + BuildOptionsModifier: func(options *types.ImageBuildOptions) {}, + }, + ExposedPorts: []string{"80/tcp"}, + Privileged: false, + ImageSubstitutors: []ImageSubstitutor{newPrependHubRegistry("localhost:5000")}, + LifecycleHooks: []ContainerLifecycleHooks{ + { + PreStarts: []ContainerHook{ + func(ctx context.Context, c Container) error { + return nil + }, + }, + }, + }, + HostConfigModifier: func(hostConfig *container.HostConfig) { + // NOOP + }, + WaitingFor: wait.ForLog("nginx: ready"), + Files: []ContainerFile{ + { + HostFilePath: tmpFile, + ContainerFilePath: "/hello.sh", + FileMode: 0755, + }, + }, + } + + hash1 := req.hash() require.NotEqual(t, 0, hash1) - hash2, err := core.Hash(req) + // modify the initial file + _, err = f.WriteString("echo goodbye gopher!") require.NoError(t, err) + + hash2 := req.hash() require.NotEqual(t, 0, hash2) - require.Equal(t, hash1, hash2) + require.Equal(t, hash1.Hash, hash2.Hash) + require.NotEqual(t, hash1.FilesHash, hash2.FilesHash) } diff --git a/request_hash.go b/request_hash.go new file mode 100644 index 0000000000..b2cbc70f1b --- /dev/null +++ b/request_hash.go @@ -0,0 +1,70 @@ +package testcontainers + +import ( + "io" + "os" + + "github.com/testcontainers/testcontainers-go/internal/core" +) + +// containerHash represents the hash of the container configuration +type containerHash struct { + // Hash of the container configuration + Hash uint64 + // Hash of the files copied to the container, to verify if they have changed + FilesHash uint64 +} + +func (c ContainerRequest) hash() containerHash { + var ch containerHash + hash, err := core.Hash(c) + if err != nil { + return ch + } + + ch = containerHash{ + Hash: hash, + } + + // The initial hash of the files copied to the container is zero. + var filesHash uint64 + + if len(c.Files) > 0 { + for _, f := range c.Files { + var fileContent []byte + // Read the file content to calculate the hash, if there is an error reading the file, + // the hash will be zero to avoid breaking the hash calculation. + if f.Reader != nil { + fileContent, err = io.ReadAll(f.Reader) + if err != nil { + continue + } + } else { + ok, err := isDir(f.HostFilePath) + if err != nil { + continue + } + + if !ok { + // Calculate the hash of the file content only if it is a file. + fileContent, err = os.ReadFile(f.HostFilePath) + if err != nil { + continue + } + } else { + // NOOP: Calculate the hash of the directory content is not supported. + } + } + + fh, err := core.Hash(fileContent) + if err != nil { + continue + } + filesHash += fh + } + + ch.FilesHash = filesHash + } + + return ch +} From 442dd4ad885c8e701c98df974e800e816e9b9431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 30 Aug 2024 08:34:28 +0200 Subject: [PATCH 04/22] chore: add labels for the container hashes --- internal/core/labels.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/internal/core/labels.go b/internal/core/labels.go index 58b054ab95..642caace68 100644 --- a/internal/core/labels.go +++ b/internal/core/labels.go @@ -5,12 +5,14 @@ import ( ) const ( - LabelBase = "org.testcontainers" - LabelLang = LabelBase + ".lang" - LabelReaper = LabelBase + ".reaper" - LabelRyuk = LabelBase + ".ryuk" - LabelSessionID = LabelBase + ".sessionId" - LabelVersion = LabelBase + ".version" + LabelBase = "org.testcontainers" + LabelLang = LabelBase + ".lang" + LabelContainerHash = LabelBase + ".hash" + LabelCopiedFilesHash = LabelBase + ".copied_files.hash" + LabelReaper = LabelBase + ".reaper" + LabelRyuk = LabelBase + ".ryuk" + LabelSessionID = LabelBase + ".sessionId" + LabelVersion = LabelBase + ".version" ) func DefaultLabels(sessionID string) map[string]string { From 969fe59145f1aa4a2ec4586d92ea730d0123071e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 30 Aug 2024 11:03:24 +0200 Subject: [PATCH 05/22] feat: reuse containers based on hashes --- container.go | 1 + docker.go | 115 +++++++++++++++++++++++-------- docker_test.go | 2 +- generic.go | 19 ++---- generic_test.go | 167 ++++++++++++++++++++-------------------------- lifecycle_test.go | 6 +- parallel_test.go | 2 +- provider.go | 2 +- 8 files changed, 173 insertions(+), 141 deletions(-) diff --git a/container.go b/container.go index 262b75d2c7..f7d6603fa1 100644 --- a/container.go +++ b/container.go @@ -140,6 +140,7 @@ type ContainerRequest struct { RegistryCred string // Deprecated: Testcontainers will detect registry credentials automatically WaitingFor wait.Strategy Name string // for specifying container name + Reuse bool `hash:"ignore"` // For reusing an existing container Hostname string WorkingDir string // specify the working directory of the container ExtraHosts []string // Deprecated: Use HostConfigModifier instead diff --git a/docker.go b/docker.go index 5f6c415627..81727679cf 100644 --- a/docker.go +++ b/docker.go @@ -1122,29 +1122,68 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque req.LifecycleHooks = []ContainerLifecycleHooks{combineContainerHooks(defaultHooks, req.LifecycleHooks)} - err = req.creatingHook(ctx) - if err != nil { - return nil, err + // calculate the hash at the end, right before creating the container + hash := req.hash() + + var resp container.CreateResponse + if req.Reuse { + // we must protect the reusability of the container in the case it's invoked + // in a parallel execution, via ParallelContainers or t.Parallel() + reuseContainerMx.Lock() + defer reuseContainerMx.Unlock() + + c, err := p.findContainerByHash(ctx, hash) + if err != nil { + return nil, err + } + + // Create a new container if the request is to reuse the container, but there is no container found by hash + if c != nil { + resp.ID = c.ID + + // replace the logging messages for reused containers + req.LifecycleHooks[0].PreCreates[0] = func(ctx context.Context, req ContainerRequest) error { + Logger.Printf("🔥 Reusing container: %s", resp.ID[:12]) + return nil + } + req.LifecycleHooks[0].PostCreates[0] = func(ctx context.Context, c Container) error { + Logger.Printf("🔥 Container reused: %s", resp.ID[:12]) + return nil + } + } } - resp, err := p.client.ContainerCreate(ctx, dockerInput, hostConfig, networkingConfig, platform, req.Name) - if err != nil { - return nil, fmt.Errorf("container create: %w", err) - } - - // #248: If there is more than one network specified in the request attach newly created container to them one by one - if len(req.Networks) > 1 { - for _, n := range req.Networks[1:] { - nw, err := p.GetNetwork(ctx, NetworkRequest{ - Name: n, - }) - if err == nil { - endpointSetting := network.EndpointSettings{ - Aliases: req.NetworkAliases[n], - } - err = p.client.NetworkConnect(ctx, nw.ID, resp.ID, &endpointSetting) - if err != nil { - return nil, fmt.Errorf("network connect: %w", err) + // If the container was not found by hash, create a new one + if resp.ID == "" { + // calculate the hash, and add the labels, just before creating the container + hash := req.hash() + req.Labels[core.LabelContainerHash] = fmt.Sprintf("%d", hash.Hash) + req.Labels[core.LabelCopiedFilesHash] = fmt.Sprintf("%d", hash.FilesHash) + + err = req.creatingHook(ctx) + if err != nil { + return nil, err + } + + resp, err = p.client.ContainerCreate(ctx, dockerInput, hostConfig, networkingConfig, platform, req.Name) + if err != nil { + return nil, fmt.Errorf("container create: %w", err) + } + + // #248: If there is more than one network specified in the request attach newly created container to them one by one + if len(req.Networks) > 1 { + for _, n := range req.Networks[1:] { + nw, err := p.GetNetwork(ctx, NetworkRequest{ + Name: n, + }) + if err == nil { + endpointSetting := network.EndpointSettings{ + Aliases: req.NetworkAliases[n], + } + err = p.client.NetworkConnect(ctx, nw.ID, resp.ID, &endpointSetting) + if err != nil { + return nil, fmt.Errorf("network connect: %w", err) + } } } } @@ -1194,10 +1233,28 @@ func (p *DockerProvider) findContainerByName(ctx context.Context, name string) ( return nil, nil } -func (p *DockerProvider) waitContainerCreation(ctx context.Context, name string) (*types.Container, error) { +func (p *DockerProvider) findContainerByHash(ctx context.Context, ch containerHash) (*types.Container, error) { + filter := filters.NewArgs( + filters.Arg("label", fmt.Sprintf("%s=%d", core.LabelContainerHash, ch.Hash)), + filters.Arg("label", fmt.Sprintf("%s=%d", core.LabelCopiedFilesHash, ch.FilesHash)), + ) + + containers, err := p.client.ContainerList(ctx, container.ListOptions{Filters: filter}) + if err != nil { + return nil, err + } + defer p.Close() + + if len(containers) > 0 { + return &containers[0], nil + } + return nil, nil +} + +func (p *DockerProvider) waitContainerCreation(ctx context.Context, hash containerHash) (*types.Container, error) { return backoff.RetryNotifyWithData( func() (*types.Container, error) { - c, err := p.findContainerByName(ctx, name) + c, err := p.findContainerByHash(ctx, hash) if err != nil { if !errdefs.IsNotFound(err) && isPermanentClientError(err) { return nil, backoff.Permanent(err) @@ -1206,7 +1263,7 @@ func (p *DockerProvider) waitContainerCreation(ctx context.Context, name string) } if c == nil { - return nil, errdefs.NotFound(fmt.Errorf("container %s not found", name)) + return nil, errdefs.NotFound(fmt.Errorf("container %v not found", hash)) } return c, nil }, @@ -1220,8 +1277,14 @@ func (p *DockerProvider) waitContainerCreation(ctx context.Context, name string) ) } +// Deprecated: it will be removed in the next major release. func (p *DockerProvider) ReuseOrCreateContainer(ctx context.Context, req ContainerRequest) (Container, error) { - c, err := p.findContainerByName(ctx, req.Name) + return p.reuseOrCreateContainer(ctx, req) +} + +func (p *DockerProvider) reuseOrCreateContainer(ctx context.Context, req ContainerRequest) (Container, error) { + hash := req.hash() + c, err := p.findContainerByHash(ctx, hash) if err != nil { return nil, err } @@ -1233,7 +1296,7 @@ func (p *DockerProvider) ReuseOrCreateContainer(ctx context.Context, req Contain if !createContainerFailDueToNameConflictRegex.MatchString(err.Error()) { return nil, err } - c, err = p.waitContainerCreation(ctx, req.Name) + c, err = p.waitContainerCreation(ctx, hash) if err != nil { return nil, err } diff --git a/docker_test.go b/docker_test.go index 402d944dce..9a708af1d9 100644 --- a/docker_test.go +++ b/docker_test.go @@ -2212,7 +2212,7 @@ func TestDockerProvider_waitContainerCreation_retries(t *testing.T) { // give a chance to retry ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() - _, _ = p.waitContainerCreation(ctx, "someID") + _, _ = p.waitContainerCreation(ctx, containerHash{}) assert.Positive(t, m.containerListCount) assert.Equal(t, tt.shouldRetry, m.containerListCount > 1) diff --git a/generic.go b/generic.go index 9052287b51..590d93c031 100644 --- a/generic.go +++ b/generic.go @@ -21,7 +21,7 @@ type GenericContainerRequest struct { Started bool // whether to auto-start the container ProviderType ProviderType // which provider to use, Docker if empty Logger Logging // provide a container specific Logging - use default global logger if empty - Reuse bool // reuse an existing container if it exists or create a new one. a container name mustn't be empty + Reuse bool // Deprecated: use ContainerRequest.Reuse instead. Reuse an existing container if it exists or create a new one. a container name mustn't be empty } // Deprecated: will be removed in the future. @@ -48,10 +48,6 @@ func GenericNetwork(ctx context.Context, req GenericNetworkRequest) (Network, er // GenericContainer creates a generic container with parameters func GenericContainer(ctx context.Context, req GenericContainerRequest) (Container, error) { - if req.Reuse && req.Name == "" { - return nil, ErrReuseEmptyName - } - logging := req.Logger if logging == nil { logging = Logger @@ -62,17 +58,12 @@ func GenericContainer(ctx context.Context, req GenericContainerRequest) (Contain } defer provider.Close() - var c Container + // transfer the reuse option to the container request if the deprecated reuse option is set if req.Reuse { - // we must protect the reusability of the container in the case it's invoked - // in a parallel execution, via ParallelContainers or t.Parallel() - reuseContainerMx.Lock() - defer reuseContainerMx.Unlock() - - c, err = provider.ReuseOrCreateContainer(ctx, req.ContainerRequest) - } else { - c, err = provider.CreateContainer(ctx, req.ContainerRequest) + req.ContainerRequest.Reuse = req.Reuse } + + c, err := provider.CreateContainer(ctx, req.ContainerRequest) if err != nil { // At this point `c` might not be nil. Give the caller an opportunity to call Destroy on the container. // TODO: Remove this debugging. diff --git a/generic_test.go b/generic_test.go index 9116fd0f65..8554c29df5 100644 --- a/generic_test.go +++ b/generic_test.go @@ -2,7 +2,6 @@ package testcontainers import ( "context" - "errors" "os" "os/exec" "strings" @@ -10,31 +9,59 @@ import ( "testing" "time" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/filters" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go/wait" ) -const ( - reusableContainerName = "my_test_reusable_container" -) +var reusableReq = ContainerRequest{ + Image: nginxDelayedImage, + ExposedPorts: []string{nginxDefaultPort}, + WaitingFor: wait.ForListeningPort(nginxDefaultPort), // default startupTimeout is 60s +} -func TestGenericReusableContainer(t *testing.T) { +func TestGenericReusableContainer_reused(t *testing.T) { ctx := context.Background() - reusableContainerName := reusableContainerName + "_" + time.Now().Format("20060102150405") + n1, err := GenericContainer(ctx, GenericContainerRequest{ + ProviderType: providerType, + ContainerRequest: reusableReq, + Started: true, + }) + require.NoError(t, err) + require.True(t, n1.IsRunning()) + terminateContainerOnEnd(t, ctx, n1) + + copiedFileName := "hello_copy.sh" + err = n1.CopyFileToContainer(ctx, "./testdata/hello.sh", "/"+copiedFileName, 700) + require.NoError(t, err) + + // because the second container is marked for reuse, the first container will be reused + old := reusableReq.Reuse + t.Cleanup(func() { + reusableReq.Reuse = old + }) + reusableReq.Reuse = true + + n2, err := GenericContainer(ctx, GenericContainerRequest{ + ProviderType: providerType, + ContainerRequest: reusableReq, + Started: true, + }) + require.NoError(t, err) + + c, _, err := n2.Exec(ctx, []string{"/bin/sh", copiedFileName}) + require.NoError(t, err) + require.Zero(t, c) +} + +func TestGenericReusableContainer_notReused(t *testing.T) { + ctx := context.Background() n1, err := GenericContainer(ctx, GenericContainerRequest{ - ProviderType: providerType, - ContainerRequest: ContainerRequest{ - Image: nginxAlpineImage, - ExposedPorts: []string{nginxDefaultPort}, - WaitingFor: wait.ForListeningPort(nginxDefaultPort), - Name: reusableContainerName, - }, - Started: true, + ProviderType: providerType, + ContainerRequest: reusableReq, + Started: true, }) require.NoError(t, err) require.True(t, n1.IsRunning()) @@ -44,66 +71,24 @@ func TestGenericReusableContainer(t *testing.T) { err = n1.CopyFileToContainer(ctx, "./testdata/hello.sh", "/"+copiedFileName, 700) require.NoError(t, err) - tests := []struct { - name string - containerName string - errorMatcher func(err error) error - reuseOption bool - }{ - { - name: "reuse option with empty name", - errorMatcher: func(err error) error { - if errors.Is(err, ErrReuseEmptyName) { - return nil - } - return err - }, - reuseOption: true, - }, - { - name: "container already exists (reuse=false)", - containerName: reusableContainerName, - errorMatcher: func(err error) error { - if err == nil { - return errors.New("expected error but got none") - } - return nil - }, - reuseOption: false, - }, - { - name: "success reusing", - containerName: reusableContainerName, - reuseOption: true, - errorMatcher: func(err error) error { - return err - }, - }, - } + // because the second container is not marked for reuse, a new container will be created + // even though the hashes are the same. + old := reusableReq.Reuse + t.Cleanup(func() { + reusableReq.Reuse = old + }) + reusableReq.Reuse = false - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - n2, err := GenericContainer(ctx, GenericContainerRequest{ - ProviderType: providerType, - ContainerRequest: ContainerRequest{ - Image: nginxAlpineImage, - ExposedPorts: []string{nginxDefaultPort}, - WaitingFor: wait.ForListeningPort(nginxDefaultPort), - Name: tc.containerName, - }, - Started: true, - Reuse: tc.reuseOption, - }) - - require.NoError(t, tc.errorMatcher(err)) - - if err == nil { - c, _, err := n2.Exec(ctx, []string{"/bin/ash", copiedFileName}) - require.NoError(t, err) - require.Zero(t, c) - } - }) - } + n2, err := GenericContainer(ctx, GenericContainerRequest{ + ProviderType: providerType, + ContainerRequest: reusableReq, + Started: true, + }) + require.NoError(t, err) + + c, _, err := n2.Exec(ctx, []string{"/bin/sh", copiedFileName}) + require.NoError(t, err) + require.NotZero(t, c) // the file does not exist in the new container, so it must fail } func TestGenericContainerShouldReturnRefOnError(t *testing.T) { @@ -145,19 +130,14 @@ func TestGenericReusableContainerInSubprocess(t *testing.T) { wg.Wait() - cli, err := NewDockerClientWithOpts(context.Background()) + provider, err := NewDockerProvider() require.NoError(t, err) - f := filters.NewArgs(filters.KeyValuePair{Key: "name", Value: reusableContainerName}) - - ctrs, err := cli.ContainerList(context.Background(), container.ListOptions{ - All: true, - Filters: f, - }) + c, err := provider.findContainerByHash(context.Background(), reusableReq.hash()) require.NoError(t, err) - require.Len(t, ctrs, 1) + require.NotNil(t, c) - nginxC, err := containerFromDockerResponse(context.Background(), ctrs[0]) + nginxC, err := containerFromDockerResponse(context.Background(), *c) require.NoError(t, err) terminateContainerOnEnd(t, context.Background(), nginxC) @@ -183,17 +163,18 @@ func TestHelperContainerStarterProcess(t *testing.T) { ctx := context.Background() + old := reusableReq.Reuse + t.Cleanup(func() { + reusableReq.Reuse = old + }) + reusableReq.Reuse = true + nginxC, err := GenericContainer(ctx, GenericContainerRequest{ - ProviderType: providerType, - ContainerRequest: ContainerRequest{ - Image: nginxDelayedImage, - ExposedPorts: []string{nginxDefaultPort}, - WaitingFor: wait.ForListeningPort(nginxDefaultPort), // default startupTimeout is 60s - Name: reusableContainerName, - }, - Started: true, - Reuse: true, + ProviderType: providerType, + ContainerRequest: reusableReq, + Started: true, }) + t.Logf("container hash: %v", reusableReq.hash()) require.NoError(t, err) require.True(t, nginxC.IsRunning()) } diff --git a/lifecycle_test.go b/lifecycle_test.go index f4b0a2ae37..3da1734668 100644 --- a/lifecycle_test.go +++ b/lifecycle_test.go @@ -545,6 +545,7 @@ func TestLifecycleHooks(t *testing.T) { // reqWithLifecycleHooks { req := ContainerRequest{ Image: nginxAlpineImage, + Reuse: tt.reuse, LifecycleHooks: []ContainerLifecycleHooks{ { PreCreates: []ContainerRequestHook{ @@ -642,13 +643,8 @@ func TestLifecycleHooks(t *testing.T) { } // } - if tt.reuse { - req.Name = "reuse-container" - } - c, err := GenericContainer(ctx, GenericContainerRequest{ ContainerRequest: req, - Reuse: tt.reuse, Started: true, }) require.NoError(t, err) diff --git a/parallel_test.go b/parallel_test.go index 122f59a4f7..eb3880e53a 100644 --- a/parallel_test.go +++ b/parallel_test.go @@ -143,9 +143,9 @@ func TestParallelContainersWithReuse(t *testing.T) { WaitingFor: wait.ForLog("database system is ready to accept connections"). WithPollInterval(100 * time.Millisecond). WithOccurrence(2), + Reuse: true, }, Started: true, - Reuse: true, } parallelRequest := ParallelContainerRequest{ diff --git a/provider.go b/provider.go index b5e5ffa997..2d5078877b 100644 --- a/provider.go +++ b/provider.go @@ -87,7 +87,7 @@ func (f GenericProviderOptionFunc) ApplyGenericTo(opts *GenericProviderOptions) type ContainerProvider interface { Close() error // close the provider CreateContainer(context.Context, ContainerRequest) (Container, error) // create a container without starting it - ReuseOrCreateContainer(context.Context, ContainerRequest) (Container, error) // reuses a container if it exists or creates a container without starting + ReuseOrCreateContainer(context.Context, ContainerRequest) (Container, error) // Deprecated: it will be removed in the next major release. Reuses a container if it exists or creates a container without starting RunContainer(context.Context, ContainerRequest) (Container, error) // create a container and start it Health(context.Context) error Config() TestcontainersConfig From c2f5e8389d58ef634e1ece06b8cec9e5b8aeb0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 30 Aug 2024 11:04:54 +0200 Subject: [PATCH 06/22] docs: document reuse --- docs/features/creating_container.md | 46 ++++++++++++++++------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md index 30264a05da..9871d0391a 100644 --- a/docs/features/creating_container.md +++ b/docs/features/creating_container.md @@ -145,11 +145,21 @@ The aforementioned `GenericContainer` function and the `ContainerRequest` struct ## Reusable container -With `Reuse` option you can reuse an existing container. Reusing will work only if you pass an -existing container name via 'req.Name' field. If the name is not in a list of existing containers, -the function will create a new generic container. If `Reuse` is true and `Name` is empty, you will get error. +With `Reuse` option you can reuse an existing container. Reusing containers works out of the box just by setting the `Reuse` field to `true`. +It will automatically create a hash of the container request and use it adding labels to the container. + +Two labels are added: + +- `org.testcontainers.hash` - set to the hash of the container request. +- `org.testcontainers.copied_files.hash` - set to the hash of the files copied to the container using the `Files` field in the container request. + +!!!info + Only the files copied in the container request will be checked for reuse. If you copy a file to a container after it has been created, as in the example below, the container will still be reused, because the original request has not changed. + +If there is no container with those two labels matching the hash values, the function will create a new generic container. Otherwise, it will reuse the existing container. The following test creates an NGINX container, adds a file into it and then reuses the container again for checking the file: + ```go package main @@ -162,20 +172,17 @@ import ( "github.com/testcontainers/testcontainers-go/wait" ) -const ( - reusableContainerName = "my_test_reusable_container" -) - func main() { ctx := context.Background() + req := testcontainers.ContainerRequest{ + Image: "nginx:1.17.6", + ExposedPorts: []string{"80/tcp"}, + WaitingFor: wait.ForListeningPort("80/tcp"), + }, + n1, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: "nginx:1.17.6", - ExposedPorts: []string{"80/tcp"}, - WaitingFor: wait.ForListeningPort("80/tcp"), - Name: reusableContainerName, - }, + ContainerRequest: req Started: true, }) if err != nil { @@ -190,15 +197,12 @@ func main() { log.Fatal(err) } + // mark the second container as reusable + req.Reuse = true + n2, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: "nginx:1.17.6", - ExposedPorts: []string{"80/tcp"}, - WaitingFor: wait.ForListeningPort("80/tcp"), - Name: reusableContainerName, - }, + ContainerRequest: req, Started: true, - Reuse: true, }) if err != nil { log.Fatal(err) @@ -212,6 +216,8 @@ func main() { } ``` +Becuase the `Reuse` option is set to `true`, the container request is the same, and the copied files have not changed, the second container is reused and the file `hello_copy.sh` will be executed. + ## Parallel running `testcontainers.ParallelContainers` - defines the containers that should be run in parallel mode. From dcbb467455f2abb639873acef4411768c8538161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 2 Sep 2024 13:53:00 +0200 Subject: [PATCH 07/22] chore: add more tests for not hashing dir contents --- hash_test.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/hash_test.go b/hash_test.go index e0d2879227..044bd37cd7 100644 --- a/hash_test.go +++ b/hash_test.go @@ -55,6 +55,80 @@ func TestHashContainerRequest(t *testing.T) { require.Equal(t, hash1.FilesHash, hash2.FilesHash) } +func TestHashContainerRequest_includingDirs(t *testing.T) { + req1 := ContainerRequest{ + Image: "nginx", + Env: map[string]string{"a": "b"}, + FromDockerfile: FromDockerfile{ + BuildOptionsModifier: func(options *types.ImageBuildOptions) {}, + }, + ExposedPorts: []string{"80/tcp"}, + Privileged: false, + ImageSubstitutors: []ImageSubstitutor{newPrependHubRegistry("localhost:5000")}, + LifecycleHooks: []ContainerLifecycleHooks{ + { + PreStarts: []ContainerHook{ + func(ctx context.Context, c Container) error { + return nil + }, + }, + }, + }, + HostConfigModifier: func(hostConfig *container.HostConfig) { + // NOOP + }, + WaitingFor: wait.ForLog("nginx: ready"), + Files: []ContainerFile{ + { + HostFilePath: "testdata", + ContainerFilePath: "/data", + FileMode: 0755, + }, + }, + } + + req2 := ContainerRequest{ + Image: "nginx", + Env: map[string]string{"a": "b"}, + FromDockerfile: FromDockerfile{ + BuildOptionsModifier: func(options *types.ImageBuildOptions) {}, + }, + ExposedPorts: []string{"80/tcp"}, + Privileged: false, + ImageSubstitutors: []ImageSubstitutor{newPrependHubRegistry("localhost:5000")}, + LifecycleHooks: []ContainerLifecycleHooks{ + { + PreStarts: []ContainerHook{ + func(ctx context.Context, c Container) error { + return nil + }, + }, + }, + }, + HostConfigModifier: func(hostConfig *container.HostConfig) { + // NOOP + }, + WaitingFor: wait.ForLog("nginx: ready"), + Files: []ContainerFile{ + { + HostFilePath: filepath.Join("testdata", "data"), + ContainerFilePath: "/data", + FileMode: 0755, + }, + }, + } + + hash1 := req1.hash() + require.NotEqual(t, 0, hash1) + + hash2 := req2.hash() + require.NotEqual(t, 0, hash2) + + require.NotEqual(t, hash1.Hash, hash2.Hash) // because the hostfile path is different + require.Zero(t, hash1.FilesHash) // the dir is not included in the hash + require.Equal(t, hash1.FilesHash, hash2.FilesHash) +} + func TestHashContainerRequest_differs(t *testing.T) { req1 := ContainerRequest{ Image: "nginx", From c07b5dc63d38c14002dcb1386910d944c99c6eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 2 Sep 2024 14:53:20 +0200 Subject: [PATCH 08/22] fix: wait for the container to be created --- docker.go | 24 ++++++++++++++++++++---- generic_test.go | 35 ++++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/docker.go b/docker.go index 81727679cf..343de04fb0 100644 --- a/docker.go +++ b/docker.go @@ -1132,8 +1132,15 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque reuseContainerMx.Lock() defer reuseContainerMx.Unlock() - c, err := p.findContainerByHash(ctx, hash) - if err != nil { + // in the case different test programs are creating a container with the same hash, + // we must check if the container is already created. For that we wait up to 5 seconds + // for the container to be created. If the error means the container is not found, we + // can proceed with the creation of the container. + // This is needed because we need to synchronize the creation of the container across + // different test programs. + c, err := p.waitContainerCreationInTimeout(ctx, hash, 5*time.Second) + if err != nil && !errdefs.IsNotFound(err) { + // another error occurred different from not found, so we return the error return nil, err } @@ -1141,7 +1148,9 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque if c != nil { resp.ID = c.ID - // replace the logging messages for reused containers + // replace the logging messages for reused containers: + // we know the first lifecycle hook is the logger hook, + // so it's safe to replace its first message for reused containers. req.LifecycleHooks[0].PreCreates[0] = func(ctx context.Context, req ContainerRequest) error { Logger.Printf("🔥 Reusing container: %s", resp.ID[:12]) return nil @@ -1252,6 +1261,13 @@ func (p *DockerProvider) findContainerByHash(ctx context.Context, ch containerHa } func (p *DockerProvider) waitContainerCreation(ctx context.Context, hash containerHash) (*types.Container, error) { + return p.waitContainerCreationInTimeout(ctx, hash, 5*time.Second) +} + +func (p *DockerProvider) waitContainerCreationInTimeout(ctx context.Context, hash containerHash, timeout time.Duration) (*types.Container, error) { + exp := backoff.NewExponentialBackOff() + exp.MaxElapsedTime = timeout + return backoff.RetryNotifyWithData( func() (*types.Container, error) { c, err := p.findContainerByHash(ctx, hash) @@ -1267,7 +1283,7 @@ func (p *DockerProvider) waitContainerCreation(ctx context.Context, hash contain } return c, nil }, - backoff.WithContext(backoff.NewExponentialBackOff(), ctx), + backoff.WithContext(exp, ctx), func(err error, duration time.Duration) { if errdefs.IsNotFound(err) { return diff --git a/generic_test.go b/generic_test.go index 8554c29df5..bc50732207 100644 --- a/generic_test.go +++ b/generic_test.go @@ -114,7 +114,16 @@ func TestGenericContainerShouldReturnRefOnError(t *testing.T) { func TestGenericReusableContainerInSubprocess(t *testing.T) { wg := sync.WaitGroup{} wg.Add(10) - for i := 0; i < 10; i++ { + + creatingMessage := "🐳 Creating container for image docker.io/menedev/delayed-nginx:1.15.2" + creatingCount := 0 + expectedCreatingCount := 1 + + reusingMessage := "🔥 Container reused" + reusingCount := 0 + expectedReusingCount := 9 + + for i := 0; i < (expectedCreatingCount + expectedReusingCount); i++ { go func() { defer wg.Done() @@ -122,25 +131,21 @@ func TestGenericReusableContainerInSubprocess(t *testing.T) { output := createReuseContainerInSubprocess(t) t.Log(output) - // check is reuse container with WaitingFor work correctly. - require.True(t, strings.Contains(output, "⏳ Waiting for container id")) - require.True(t, strings.Contains(output, "🔔 Container is ready")) + + if strings.Contains(output, creatingMessage) { + creatingCount++ + } + + if strings.Contains(output, reusingMessage) { + reusingCount++ + } }() } wg.Wait() - provider, err := NewDockerProvider() - require.NoError(t, err) - - c, err := provider.findContainerByHash(context.Background(), reusableReq.hash()) - require.NoError(t, err) - require.NotNil(t, c) - - nginxC, err := containerFromDockerResponse(context.Background(), *c) - require.NoError(t, err) - - terminateContainerOnEnd(t, context.Background(), nginxC) + require.Equal(t, expectedCreatingCount, creatingCount) + require.Equal(t, expectedReusingCount, reusingCount) } func createReuseContainerInSubprocess(t *testing.T) string { From d1d40ce2290ff5ae6ae7620db226b7e8e7c9dfe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 2 Sep 2024 16:50:18 +0200 Subject: [PATCH 09/22] chore: simplify deprecation --- docker.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docker.go b/docker.go index 343de04fb0..7aab0cc7ee 100644 --- a/docker.go +++ b/docker.go @@ -1295,10 +1295,6 @@ func (p *DockerProvider) waitContainerCreationInTimeout(ctx context.Context, has // Deprecated: it will be removed in the next major release. func (p *DockerProvider) ReuseOrCreateContainer(ctx context.Context, req ContainerRequest) (Container, error) { - return p.reuseOrCreateContainer(ctx, req) -} - -func (p *DockerProvider) reuseOrCreateContainer(ctx context.Context, req ContainerRequest) (Container, error) { hash := req.hash() c, err := p.findContainerByHash(ctx, hash) if err != nil { From 7aa26da846a362c1188af6cd6a715485d4ca9889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Tue, 3 Sep 2024 18:29:13 +0200 Subject: [PATCH 10/22] docs: improve docs for reuse --- docs/features/creating_container.md | 53 ++++++++++++++++++----------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md index 9871d0391a..5a47e881f7 100644 --- a/docs/features/creating_container.md +++ b/docs/features/creating_container.md @@ -145,23 +145,28 @@ The aforementioned `GenericContainer` function and the `ContainerRequest` struct ## Reusable container -With `Reuse` option you can reuse an existing container. Reusing containers works out of the box just by setting the `Reuse` field to `true`. -It will automatically create a hash of the container request and use it adding labels to the container. +!!!warning + Reusing containers is an experimental feature and you can experience some issues while using it in your tests. If you find any issue, please report it creating an issue [here](https://github.com/testcontainers/testcontainers-go/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D%3A+). -Two labels are added: +A `ReusableContainer` is a container you mark to be reused across different tests. Reusing containers works out of the box just by setting the `Reuse` field to `true`. +Internally, _Testcontainers for Go_ automatically creates a hash of the container request and adds it as a container label. Two labels are added: -- `org.testcontainers.hash` - set to the hash of the container request. -- `org.testcontainers.copied_files.hash` - set to the hash of the files copied to the container using the `Files` field in the container request. +- `org.testcontainers.hash` - the hash of the container request. +- `org.testcontainers.copied_files.hash` - the hash of the files copied to the container using the `Files` field in the container request. !!!info Only the files copied in the container request will be checked for reuse. If you copy a file to a container after it has been created, as in the example below, the container will still be reused, because the original request has not changed. -If there is no container with those two labels matching the hash values, the function will create a new generic container. Otherwise, it will reuse the existing container. +If there is no container with those two labels matching the hash values, the function will create a new container. Otherwise, it will reuse the existing container. + +This behaviour persists across multiple test runs, as long as the container request remains the same. Ryuk the resource reaper won't terminate that container if it is marked for reuse, as it won't match the prune conditions used by Ryuk. + +### Reuse example The following test creates an NGINX container, adds a file into it and then reuses the container again for checking the file: ```go -package main +package testcontainers_test import ( "context" @@ -172,37 +177,42 @@ import ( "github.com/testcontainers/testcontainers-go/wait" ) -func main() { +func ExampleReusableContainer_usingACopiedFile() { ctx := context.Background() req := testcontainers.ContainerRequest{ Image: "nginx:1.17.6", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForListeningPort("80/tcp"), - }, + Reuse: true, // mark the container as reusable + } n1, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ - ContainerRequest: req - Started: true, + ContainerRequest: req, + Started: true, }) if err != nil { log.Fatal(err) } - defer n1.Terminate(ctx) + // not terminating the container on purpose, so that it can be reused in a different test. + // defer n1.Terminate(ctx) - copiedFileName := "hello_copy.sh" - err = n1.CopyFileToContainer(ctx, "./testdata/hello.sh", "/"+copiedFileName, 700) + // Let's copy a file to the container, to demonstrate that successive containers can use the same files + // when the container is marked for reuse. + bs := []byte(`#!/usr/bin/env bash +echo "hello world" > /data/hello.txt +echo "done"`) + copiedFileName := "hello_copy.sh" + err = n1.CopyToContainer(ctx, bs, "/"+copiedFileName, 700) if err != nil { log.Fatal(err) } - // mark the second container as reusable - req.Reuse = true - + // Because n2 uses the same container request, it will reuse the container created by n1. n2, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: req, - Started: true, + Started: true, }) if err != nil { log.Fatal(err) @@ -212,11 +222,16 @@ func main() { if err != nil { log.Fatal(err) } + + // the file must exist in this second container, as it's reusing the first one fmt.Println(c) + + // Output: 0 } + ``` -Becuase the `Reuse` option is set to `true`, the container request is the same, and the copied files have not changed, the second container is reused and the file `hello_copy.sh` will be executed. +Becuase the `Reuse` option is set to `true`, and the copied files have not changed, the container request is the same, resulting in the second container reusing the first one and the file `hello_copy.sh` being executed. ## Parallel running From 35da30a015506098e6d3cf3568e9ef57d012b18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Tue, 3 Sep 2024 18:29:38 +0200 Subject: [PATCH 11/22] feat: do not remove the container with Ryuk Removing the sessionID label, it won't be pruned by Ryuk --- docker.go | 6 ++++++ docs/features/creating_container.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docker.go b/docker.go index 7aab0cc7ee..df4bd09fda 100644 --- a/docker.go +++ b/docker.go @@ -1122,6 +1122,12 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque req.LifecycleHooks = []ContainerLifecycleHooks{combineContainerHooks(defaultHooks, req.LifecycleHooks)} + if req.Reuse { + // Remove the SessionID label from the request, as we don't want Ryuk to control + // the container lifecycle in the case of reusing containers. + delete(req.Labels, core.LabelSessionID) + } + // calculate the hash at the end, right before creating the container hash := req.hash() diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md index 5a47e881f7..b2dcdcc4ce 100644 --- a/docs/features/creating_container.md +++ b/docs/features/creating_container.md @@ -163,7 +163,7 @@ This behaviour persists across multiple test runs, as long as the container requ ### Reuse example -The following test creates an NGINX container, adds a file into it and then reuses the container again for checking the file: +The following example creates an NGINX container, adds a file into it and then reuses the container again for checking the file: ```go package testcontainers_test From 0ffec348ec9efe4ac5f0f2fd827b3a0599a7c8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 12:50:20 +0200 Subject: [PATCH 12/22] docs: enrich reuse docs --- docs/features/common_functional_options.md | 14 +++++++++++++- docs/features/creating_container.md | 2 +- docs/modules/index.md | 7 ++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/docs/features/common_functional_options.md b/docs/features/common_functional_options.md index d559a3ee7f..c0681d362a 100644 --- a/docs/features/common_functional_options.md +++ b/docs/features/common_functional_options.md @@ -135,6 +135,18 @@ If you want to attach your containers to a throw-away network, you can use the ` In the case you need to retrieve the network name, you can use the `Networks(ctx)` method of the `Container` interface, right after it's running, which returns a slice of strings with the names of the networks where the container is attached. +#### WithReuse + +- Not available until the next release of testcontainers-go :material-tag: main + +If you want to reuse a container across different test executions, you can use `testcontainers.WithReuse` option. This option will keep the container running after the test execution, and it will be reused by any other test sharing the same `ContainerRequest`: + +```golang +postgres, err = postgresModule.Run(ctx, "postgres:15-alpine", testcontainers.WithReuse()) +``` + +Please read the [Reuse containers](/features/creating_container#reusable-container) documentation for more information. + #### Docker type modifiers If you need an advanced configuration for the container, you can leverage the following Docker type modifiers: @@ -143,7 +155,7 @@ If you need an advanced configuration for the container, you can leverage the fo - `testcontainers.WithHostConfigModifier` - `testcontainers.WithEndpointSettingsModifier` -Please read the [Create containers: Advanced Settings](/features/creating_container.md#advanced-settings) documentation for more information. +Please read the [Create containers: Advanced Settings](/features/creating_container#advanced-settings) documentation for more information. #### Customising the ContainerRequest diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md index b2dcdcc4ce..34564c3c95 100644 --- a/docs/features/creating_container.md +++ b/docs/features/creating_container.md @@ -146,7 +146,7 @@ The aforementioned `GenericContainer` function and the `ContainerRequest` struct ## Reusable container !!!warning - Reusing containers is an experimental feature and you can experience some issues while using it in your tests. If you find any issue, please report it creating an issue [here](https://github.com/testcontainers/testcontainers-go/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D%3A+). + Reusing containers is an experimental feature, so please acknowledge you can experience some issues while using it. If you find any issue, please report it [here](https://github.com/testcontainers/testcontainers-go/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D%3A+). A `ReusableContainer` is a container you mark to be reused across different tests. Reusing containers works out of the box just by setting the `Reuse` field to `true`. Internally, _Testcontainers for Go_ automatically creates a hash of the container request and adds it as a container label. Two labels are added: diff --git a/docs/modules/index.md b/docs/modules/index.md index 629787fedf..a01828a6d6 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -202,9 +202,10 @@ In order to simplify the creation of the container for a given module, `Testcont - `testcontainers.WithAfterReadyCommand`: a function that sets the execution of a command right after the container is ready (its wait strategy is satisfied). - `testcontainers.WithNetwork`: a function that sets the network and the network aliases for the container request. - `testcontainers.WithNewNetwork`: a function that sets the network aliases for a throw-away network for the container request. -- `testcontainers.WithConfigModifier`: a function that sets the config Docker type for the container request. Please see [Advanced Settings](../features/creating_container.md#advanced-settings) for more information. -- `testcontainers.WithEndpointSettingsModifier`: a function that sets the endpoint settings Docker type for the container request. Please see [Advanced Settings](../features/creating_container.md#advanced-settings) for more information. -- `testcontainers.WithHostConfigModifier`: a function that sets the host config Docker type for the container request. Please see [Advanced Settings](../features/creating_container.md#advanced-settings) for more information. +- `testcontainers.WithReuse`: a function that marks the container to be reused. Please see [Reusing containers](../features/creating_container#reusable-container) for more information. +- `testcontainers.WithConfigModifier`: a function that sets the config Docker type for the container request. Please see [Advanced Settings](../features/creating_container#advanced-settings) for more information. +- `testcontainers.WithEndpointSettingsModifier`: a function that sets the endpoint settings Docker type for the container request. Please see [Advanced Settings](../features/creating_container#advanced-settings) for more information. +- `testcontainers.WithHostConfigModifier`: a function that sets the host config Docker type for the container request. Please see [Advanced Settings](../features/creating_container#advanced-settings) for more information. - `testcontainers.WithWaitStrategy`: a function that sets the wait strategy for the container request, adding all the passed wait strategies to the container request, using a `testcontainers.MultiStrategy` with 60 seconds of deadline. Please see [Wait strategies](../features/wait/multi.md) for more information. - `testcontainers.WithWaitStrategyAndDeadline`: a function that sets the wait strategy for the container request, adding all the passed wait strategies to the container request, using a `testcontainers.MultiStrategy` with the passed deadline. Please see [Wait strategies](../features/wait/multi.md) for more information. - `testcontainers.CustomizeRequest`: a function that merges the default options with the ones provided by the user. Recommended for completely customizing the container request. From 7a505ba8276fd860665cdc43be4722524267c922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 12:56:14 +0200 Subject: [PATCH 13/22] feat: support modules to be reused --- options.go | 9 +++++++++ options_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/options.go b/options.go index 2849b15667..931d854500 100644 --- a/options.go +++ b/options.go @@ -321,6 +321,15 @@ func WithAfterReadyCommand(execs ...Executable) CustomizeRequestOption { } } +// WithReuse allows to reuse the container for multiple tests +func WithReuse() CustomizeRequestOption { + return func(req *GenericContainerRequest) error { + req.Reuse = true // update deprecated field too + req.ContainerRequest.Reuse = true + return nil + } +} + // WithWaitStrategy sets the wait strategy for a container, using 60 seconds as deadline func WithWaitStrategy(strategies ...wait.Strategy) CustomizeRequestOption { return WithWaitStrategyAndDeadline(60*time.Second, strategies...) diff --git a/options_test.go b/options_test.go index e19ecde96e..0cc180f6c1 100644 --- a/options_test.go +++ b/options_test.go @@ -245,3 +245,28 @@ func TestWithHostPortAccess(t *testing.T) { }) } } + +func TestWithReuse(t *testing.T) { + tests := []struct { + name string + req *testcontainers.GenericContainerRequest + expect bool + }{ + { + name: "Mark for reuse", + req: &testcontainers.GenericContainerRequest{ + ContainerRequest: testcontainers.ContainerRequest{}, + }, + expect: true, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + opt := testcontainers.WithReuse() + + require.NoError(t, opt.Customize(tc.req)) + require.Equal(t, tc.expect, tc.req.Reuse) + require.Equal(t, tc.expect, tc.req.ContainerRequest.Reuse) + }) + } +} From a544bc0222f8ab37c30f839a8bba07604f43d38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 13:02:27 +0200 Subject: [PATCH 14/22] docs: refinement --- docs/features/common_functional_options.md | 2 +- docs/features/creating_container.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/features/common_functional_options.md b/docs/features/common_functional_options.md index c0681d362a..88beba1756 100644 --- a/docs/features/common_functional_options.md +++ b/docs/features/common_functional_options.md @@ -139,7 +139,7 @@ In the case you need to retrieve the network name, you can use the `Networks(ctx - Not available until the next release of testcontainers-go :material-tag: main -If you want to reuse a container across different test executions, you can use `testcontainers.WithReuse` option. This option will keep the container running after the test execution, and it will be reused by any other test sharing the same `ContainerRequest`: +If you want to reuse a container across different test executions, you can use `testcontainers.WithReuse` option. This option will keep the container running after the test execution, so it can be reused by any other test sharing the same `ContainerRequest`. As a result, the container is not terminated by Ryuk. ```golang postgres, err = postgresModule.Run(ctx, "postgres:15-alpine", testcontainers.WithReuse()) diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md index 34564c3c95..21846874f5 100644 --- a/docs/features/creating_container.md +++ b/docs/features/creating_container.md @@ -148,18 +148,18 @@ The aforementioned `GenericContainer` function and the `ContainerRequest` struct !!!warning Reusing containers is an experimental feature, so please acknowledge you can experience some issues while using it. If you find any issue, please report it [here](https://github.com/testcontainers/testcontainers-go/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D%3A+). -A `ReusableContainer` is a container you mark to be reused across different tests. Reusing containers works out of the box just by setting the `Reuse` field to `true`. +A `ReusableContainer` is a container you mark to be reused across different tests. Reusing containers works out of the box just by setting the `Reuse` field in the `ContainerRequest` to `true`. Internally, _Testcontainers for Go_ automatically creates a hash of the container request and adds it as a container label. Two labels are added: - `org.testcontainers.hash` - the hash of the container request. - `org.testcontainers.copied_files.hash` - the hash of the files copied to the container using the `Files` field in the container request. !!!info - Only the files copied in the container request will be checked for reuse. If you copy a file to a container after it has been created, as in the example below, the container will still be reused, because the original request has not changed. + Only the files copied in the container request will be checked for reuse. If you copy a file to a container after it has been created, as in the example below, the container will still be reused, because the original request has not changed. Directories added in the `Files` field are not included in the hash, to avoid performance issues calculating the hash of large directories. -If there is no container with those two labels matching the hash values, the function will create a new container. Otherwise, it will reuse the existing container. +If there is no container with those two labels matching the hash values, _Testcontainers for Go_ creates a new container. Otherwise, it reuses the existing one. -This behaviour persists across multiple test runs, as long as the container request remains the same. Ryuk the resource reaper won't terminate that container if it is marked for reuse, as it won't match the prune conditions used by Ryuk. +This behaviour persists across multiple test runs, as long as the container request remains the same. Ryuk the resource reaper does not terminate that container if it is marked for reuse, as it does not match the prune conditions used by Ryuk. To know more about Ryuk, please read the [Garbage Collector](/features/garbage_collector#ryuk) documentation. ### Reuse example From c9356edb529c6ed8a1f7194a8d3d10648d0e7440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 13:21:44 +0200 Subject: [PATCH 15/22] chore: adjust tests --- generic_test.go | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/generic_test.go b/generic_test.go index bc50732207..9f3fb7be6f 100644 --- a/generic_test.go +++ b/generic_test.go @@ -18,6 +18,7 @@ var reusableReq = ContainerRequest{ Image: nginxDelayedImage, ExposedPorts: []string{nginxDefaultPort}, WaitingFor: wait.ForListeningPort(nginxDefaultPort), // default startupTimeout is 60s + Reuse: true, } func TestGenericReusableContainer_reused(t *testing.T) { @@ -36,13 +37,6 @@ func TestGenericReusableContainer_reused(t *testing.T) { err = n1.CopyFileToContainer(ctx, "./testdata/hello.sh", "/"+copiedFileName, 700) require.NoError(t, err) - // because the second container is marked for reuse, the first container will be reused - old := reusableReq.Reuse - t.Cleanup(func() { - reusableReq.Reuse = old - }) - reusableReq.Reuse = true - n2, err := GenericContainer(ctx, GenericContainerRequest{ ProviderType: providerType, ContainerRequest: reusableReq, @@ -73,11 +67,11 @@ func TestGenericReusableContainer_notReused(t *testing.T) { // because the second container is not marked for reuse, a new container will be created // even though the hashes are the same. - old := reusableReq.Reuse + old := reusableReq t.Cleanup(func() { - reusableReq.Reuse = old + reusableReq = old }) - reusableReq.Reuse = false + reusableReq.Hostname = "foo" n2, err := GenericContainer(ctx, GenericContainerRequest{ ProviderType: providerType, @@ -85,6 +79,7 @@ func TestGenericReusableContainer_notReused(t *testing.T) { Started: true, }) require.NoError(t, err) + terminateContainerOnEnd(t, ctx, n2) c, _, err := n2.Exec(ctx, []string{"/bin/sh", copiedFileName}) require.NoError(t, err) @@ -168,12 +163,6 @@ func TestHelperContainerStarterProcess(t *testing.T) { ctx := context.Background() - old := reusableReq.Reuse - t.Cleanup(func() { - reusableReq.Reuse = old - }) - reusableReq.Reuse = true - nginxC, err := GenericContainer(ctx, GenericContainerRequest{ ProviderType: providerType, ContainerRequest: reusableReq, From 1f66181381a4f57a6376e670ab7e9ffe5124453c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 13:45:28 +0200 Subject: [PATCH 16/22] chore: adapt test to flakiness --- generic_test.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/generic_test.go b/generic_test.go index 9f3fb7be6f..79148cb2dd 100644 --- a/generic_test.go +++ b/generic_test.go @@ -110,15 +110,17 @@ func TestGenericReusableContainerInSubprocess(t *testing.T) { wg := sync.WaitGroup{} wg.Add(10) - creatingMessage := "🐳 Creating container for image docker.io/menedev/delayed-nginx:1.15.2" + creatingMessage := "🐳 Creating container for image " + nginxDelayedImage creatingCount := 0 - expectedCreatingCount := 1 reusingMessage := "🔥 Container reused" reusingCount := 0 - expectedReusingCount := 9 - for i := 0; i < (expectedCreatingCount + expectedReusingCount); i++ { + minCreatedCount := 1 + maxReusedCount := 9 + totalCount := minCreatedCount + maxReusedCount + + for i := 0; i < totalCount; i++ { go func() { defer wg.Done() @@ -139,8 +141,17 @@ func TestGenericReusableContainerInSubprocess(t *testing.T) { wg.Wait() - require.Equal(t, expectedCreatingCount, creatingCount) - require.Equal(t, expectedReusingCount, reusingCount) + // because we cannot guarantee the daemon will reuse the container, we can only assert that + // the container was created at least once and reused at least once. This flakiness is due to + // the fact that the code is checking for a few seconds if the container with the hash labels is + // already running, and because this test is using separate test processes, it could be possible + // that the container is not reused in time. + // This flakiness is documented in the Reuse docs, so this test demonstrates that is usually working. + t.Logf("Created: %v, Reused: %v, Total: %v", creatingCount, reusingCount, totalCount) + + require.LessOrEqual(t, creatingCount, totalCount) + require.LessOrEqual(t, reusingCount, totalCount) + require.Equal(t, totalCount, reusingCount+creatingCount) } func createReuseContainerInSubprocess(t *testing.T) string { From 31e54b9578e4c34de5858b311cc8cd2a3fd30e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 13:45:55 +0200 Subject: [PATCH 17/22] chore: calculate hash at the right time --- docker.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/docker.go b/docker.go index df4bd09fda..4cabc84efc 100644 --- a/docker.go +++ b/docker.go @@ -1128,9 +1128,6 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque delete(req.Labels, core.LabelSessionID) } - // calculate the hash at the end, right before creating the container - hash := req.hash() - var resp container.CreateResponse if req.Reuse { // we must protect the reusability of the container in the case it's invoked @@ -1138,6 +1135,11 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque reuseContainerMx.Lock() defer reuseContainerMx.Unlock() + // calculate the hash, and add the labels, just before creating the container + hash := req.hash() + req.Labels[core.LabelContainerHash] = fmt.Sprintf("%d", hash.Hash) + req.Labels[core.LabelCopiedFilesHash] = fmt.Sprintf("%d", hash.FilesHash) + // in the case different test programs are creating a container with the same hash, // we must check if the container is already created. For that we wait up to 5 seconds // for the container to be created. If the error means the container is not found, we @@ -1170,11 +1172,6 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque // If the container was not found by hash, create a new one if resp.ID == "" { - // calculate the hash, and add the labels, just before creating the container - hash := req.hash() - req.Labels[core.LabelContainerHash] = fmt.Sprintf("%d", hash.Hash) - req.Labels[core.LabelCopiedFilesHash] = fmt.Sprintf("%d", hash.FilesHash) - err = req.creatingHook(ctx) if err != nil { return nil, err From 44b1b73b4471b4ad3bf8e0f5d7429b839aebd318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 17:24:59 +0200 Subject: [PATCH 18/22] chore: improve the subprocess tests --- generic_test.go | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/generic_test.go b/generic_test.go index 79148cb2dd..14e42ca166 100644 --- a/generic_test.go +++ b/generic_test.go @@ -2,6 +2,7 @@ package testcontainers import ( "context" + "fmt" "os" "os/exec" "strings" @@ -9,11 +10,18 @@ import ( "testing" "time" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go/internal/core" "github.com/testcontainers/testcontainers-go/wait" ) +const ( + reusableMarkerTestLabel string = "TEST_REUSABLE_MARKER" +) + var reusableReq = ContainerRequest{ Image: nginxDelayedImage, ExposedPorts: []string{nginxDefaultPort}, @@ -152,6 +160,24 @@ func TestGenericReusableContainerInSubprocess(t *testing.T) { require.LessOrEqual(t, creatingCount, totalCount) require.LessOrEqual(t, reusingCount, totalCount) require.Equal(t, totalCount, reusingCount+creatingCount) + + // cleanup the containers that could have been created in the subprocesses + + cli, err := core.NewClient(context.Background()) + require.NoError(t, err) + + // We need to find the containers created in the subprocesses and terminate them. + // For that, we are going to search for containers with the reusable test label. + f := filters.NewArgs(filters.Arg("label", fmt.Sprintf("%s=%s", reusableMarkerTestLabel, "true"))) + cs, err := cli.ContainerList(context.Background(), container.ListOptions{Filters: f}) + require.NoError(t, err) + defer cli.Close() + + for _, c := range cs { + dc, err := containerFromDockerResponse(context.Background(), c) + require.NoError(t, err) + require.NoError(t, dc.Terminate(context.Background())) + } } func createReuseContainerInSubprocess(t *testing.T) string { @@ -174,12 +200,18 @@ func TestHelperContainerStarterProcess(t *testing.T) { ctx := context.Background() + // we are going to mark the container with a test label, so that we can find it later + req := reusableReq + if req.Labels == nil { + req.Labels = map[string]string{} + } + req.Labels[reusableMarkerTestLabel] = "true" + nginxC, err := GenericContainer(ctx, GenericContainerRequest{ ProviderType: providerType, - ContainerRequest: reusableReq, + ContainerRequest: req, Started: true, }) - t.Logf("container hash: %v", reusableReq.hash()) require.NoError(t, err) require.True(t, nginxC.IsRunning()) } From 781ade74660c3053507ea11bd963d78342bfeedb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 17:25:18 +0200 Subject: [PATCH 19/22] chore: make lint --- hash_test.go | 12 ++++++------ internal/core/hash_test.go | 1 + request_hash.go | 3 +-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hash_test.go b/hash_test.go index 044bd37cd7..9fe0a1e2ea 100644 --- a/hash_test.go +++ b/hash_test.go @@ -40,7 +40,7 @@ func TestHashContainerRequest(t *testing.T) { { HostFilePath: filepath.Join("testdata", "hello.sh"), ContainerFilePath: "/hello.sh", - FileMode: 0755, + FileMode: 0o755, }, }, } @@ -82,7 +82,7 @@ func TestHashContainerRequest_includingDirs(t *testing.T) { { HostFilePath: "testdata", ContainerFilePath: "/data", - FileMode: 0755, + FileMode: 0o755, }, }, } @@ -113,7 +113,7 @@ func TestHashContainerRequest_includingDirs(t *testing.T) { { HostFilePath: filepath.Join("testdata", "data"), ContainerFilePath: "/data", - FileMode: 0755, + FileMode: 0o755, }, }, } @@ -156,7 +156,7 @@ func TestHashContainerRequest_differs(t *testing.T) { { HostFilePath: filepath.Join("testdata", "hello.sh"), ContainerFilePath: "/hello.sh", - FileMode: 0755, + FileMode: 0o755, }, }, } @@ -187,7 +187,7 @@ func TestHashContainerRequest_differs(t *testing.T) { { HostFilePath: filepath.Join("testdata", "hello.sh"), ContainerFilePath: "/hello.sh", - FileMode: 0755, + FileMode: 0o755, }, }, } @@ -240,7 +240,7 @@ func TestHashContainerRequest_modifiedFiles(t *testing.T) { { HostFilePath: tmpFile, ContainerFilePath: "/hello.sh", - FileMode: 0755, + FileMode: 0o755, }, }, } diff --git a/internal/core/hash_test.go b/internal/core/hash_test.go index abba7461bf..bb3bdfd853 100644 --- a/internal/core/hash_test.go +++ b/internal/core/hash_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go/internal/core" ) diff --git a/request_hash.go b/request_hash.go index b2cbc70f1b..2801fd52d0 100644 --- a/request_hash.go +++ b/request_hash.go @@ -51,9 +51,8 @@ func (c ContainerRequest) hash() containerHash { if err != nil { continue } - } else { - // NOOP: Calculate the hash of the directory content is not supported. } + // The else of this condition is a NOOP, as calculating the hash of the directory content is not supported. } fh, err := core.Hash(fileContent) From e975ae99ea5698da4ab1b7346440d00b5621a537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 17:49:14 +0200 Subject: [PATCH 20/22] chore: no need to ignore Reuse --- container.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/container.go b/container.go index f7d6603fa1..7a85a60458 100644 --- a/container.go +++ b/container.go @@ -140,7 +140,7 @@ type ContainerRequest struct { RegistryCred string // Deprecated: Testcontainers will detect registry credentials automatically WaitingFor wait.Strategy Name string // for specifying container name - Reuse bool `hash:"ignore"` // For reusing an existing container + Reuse bool // For reusing an existing container Hostname string WorkingDir string // specify the working directory of the container ExtraHosts []string // Deprecated: Use HostConfigModifier instead From dd9190116bb7a74ccb3ac96917c1dad80d6c6fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 4 Sep 2024 18:15:49 +0200 Subject: [PATCH 21/22] docs: warn about flakiness in concurrent executions --- docs/features/creating_container.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/features/creating_container.md b/docs/features/creating_container.md index 21846874f5..e1257e1370 100644 --- a/docs/features/creating_container.md +++ b/docs/features/creating_container.md @@ -161,6 +161,13 @@ If there is no container with those two labels matching the hash values, _Testco This behaviour persists across multiple test runs, as long as the container request remains the same. Ryuk the resource reaper does not terminate that container if it is marked for reuse, as it does not match the prune conditions used by Ryuk. To know more about Ryuk, please read the [Garbage Collector](/features/garbage_collector#ryuk) documentation. +!!!warning + In the case different test programs are creating a container with the same hash, we must check if the container is already created. + For that _Testcontainers for Go_ waits up-to 5 seconds for the container to be created. If the container is not found, + the code proceedes with the creation of the container, else the container is reused. + This wait is needed because we need to synchronize the creation of the container across different test programs, + so you could find very rare situations where the container is not found in different test sessions and it is created in them. + ### Reuse example The following example creates an NGINX container, adds a file into it and then reuses the container again for checking the file: From 799ee150afa508ce4b9f6e517ac457ecf8176d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 5 Sep 2024 10:51:18 +0200 Subject: [PATCH 22/22] docs: do not use postgres in funcitonal options --- docs/features/common_functional_options.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/features/common_functional_options.md b/docs/features/common_functional_options.md index 88beba1756..8db0e7e1ee 100644 --- a/docs/features/common_functional_options.md +++ b/docs/features/common_functional_options.md @@ -32,7 +32,7 @@ postgres, err = postgresModule.Run(ctx, "postgres:15-alpine", testcontainers.Wit If you need to access a port that is already running in the host, you can use `testcontainers.WithHostPortAccess` for example: ```golang -postgres, err = postgresModule.Run(ctx, "postgres:15-alpine", testcontainers.WithHostPortAccess(8080)) +ctr, err = tcmodule.Run(ctx, "your-image:your-tag", testcontainers.WithHostPortAccess(8080)) ``` To understand more about this feature, please read the [Exposing host ports to the container](/features/networking/#exposing-host-ports-to-the-container) documentation. @@ -70,7 +70,7 @@ useful context instead of appearing out of band. ```golang func TestHandler(t *testing.T) { logger := TestLogger(t) - _, err := postgresModule.Run(ctx, "postgres:15-alpine", testcontainers.WithLogger(logger)) + _, err := postgresModule.Run(ctx, "your-image:your-tag", testcontainers.WithLogger(logger)) require.NoError(t, err) // Do something with container. } @@ -142,7 +142,7 @@ In the case you need to retrieve the network name, you can use the `Networks(ctx If you want to reuse a container across different test executions, you can use `testcontainers.WithReuse` option. This option will keep the container running after the test execution, so it can be reused by any other test sharing the same `ContainerRequest`. As a result, the container is not terminated by Ryuk. ```golang -postgres, err = postgresModule.Run(ctx, "postgres:15-alpine", testcontainers.WithReuse()) +ctr, err = tcmodule.Run(ctx, "your-image:your-tag", testcontainers.WithReuse()) ``` Please read the [Reuse containers](/features/creating_container#reusable-container) documentation for more information. @@ -162,7 +162,7 @@ Please read the [Create containers: Advanced Settings](/features/creating_contai This option will merge the customized request into the module's own `ContainerRequest`. ```go -container, err := Run(ctx, "postgres:13-alpine", +ctr, err := Run(ctx, "your-image:your-tag", /* Other module options */ testcontainers.CustomizeRequest(testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{