From 0ce34a8eef49c139cdedb2165398b5be676656d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 2 Nov 2023 18:01:49 +0100 Subject: [PATCH] feat: expose a WithNetwork functional option (#1887) * feat: move WithNetwork functional option to the core * chore: reuse the network if it already existed --- docs/features/common_functional_options.md | 8 ++++++ docs/modules/localstack.md | 4 --- generic.go | 31 ++++++++++++++++++++++ modules/localstack/localstack.go | 24 ++--------------- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/docs/features/common_functional_options.md b/docs/features/common_functional_options.md index 820925b2bd..1eedfbd8ea 100644 --- a/docs/features/common_functional_options.md +++ b/docs/features/common_functional_options.md @@ -28,6 +28,14 @@ It also exports an `Executable` interface, defining one single method: `AsComman You could use this feature to run a custom script, or to run a command that is not supported by the module right after the container is started. +#### WithNetwork + +- Not available until the next release of testcontainers-go :material-tag: main + +By default, the container is started in the default Docker network. If you want to use a different Docker network, you can use the `WithNetwork(networkName string, alias string)` option, which receives the new network name and an alias as parameters, creating the new network, attaching the container to it, and setting the network alias for that network. + +If the network already exists, _Testcontainers for Go_ won't create a new one, but it will attach the container to it and set the network alias. + #### Docker type modifiers If you need an advanced configuration for the container, you can leverage the following Docker type modifiers: diff --git a/docs/modules/localstack.md b/docs/modules/localstack.md index b965ae9add..25a225b6c3 100644 --- a/docs/modules/localstack.md +++ b/docs/modules/localstack.md @@ -58,10 +58,6 @@ With simply passing the `testcontainers.CustomizeRequest` functional option to t In the above example you can check how it's possible to set certain environment variables that are needed by the tests, the most important ones are the AWS services you want to use. Besides, the container runs in a separate Docker network with an alias. -#### WithNetwork - -By default, the LocalStack container is started in the default Docker network. If you want to use a different Docker network, you can use the `WithNetwork(networkName string, alias string)` option, which receives the new network name and an alias as parameters, creating the new network, attaching the container to it, and setting the network alias for that network. - ## Accessing hostname-sensitive services Some Localstack APIs, such as SQS, require the container to be aware of the hostname that it is accessible on - for example, for construction of queue URLs in responses. diff --git a/generic.go b/generic.go index c5b8ccf2aa..cedc96e704 100644 --- a/generic.go +++ b/generic.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strings" "sync" "time" @@ -101,6 +102,36 @@ func WithHostConfigModifier(modifier func(hostConfig *container.HostConfig)) Cus } } +// WithNetwork creates a network with the given name and attaches the container to it, setting the network alias +// on that network to the given alias. +// If the network already exists, checking if the network name already exists, it will be reused. +func WithNetwork(networkName string, alias string) CustomizeRequestOption { + return func(req *GenericContainerRequest) { + _, err := GenericNetwork(context.Background(), GenericNetworkRequest{ + NetworkRequest: NetworkRequest{ + Name: networkName, + CheckDuplicate: true, // force the Docker provider to reuse an existing network + }, + }) + if err != nil && !strings.Contains(err.Error(), "already exists") { + logger := req.Logger + if logger == nil { + logger = Logger + } + logger.Printf("Failed to create network '%s'. Container won't be attached to this network: %v", networkName, err) + return + } + + // attaching to the network because it was created with success or it already existed. + req.Networks = append(req.Networks, networkName) + + if req.NetworkAliases == nil { + req.NetworkAliases = make(map[string][]string) + } + req.NetworkAliases[networkName] = []string{alias} + } +} + // Executable represents an executable command to be sent to a container // as part of the PostStart lifecycle hook. type Executable interface { diff --git a/modules/localstack/localstack.go b/modules/localstack/localstack.go index 48b6e03f25..d4c3dee1ba 100644 --- a/modules/localstack/localstack.go +++ b/modules/localstack/localstack.go @@ -61,29 +61,9 @@ func isVersion2(image string) bool { // WithNetwork creates a network with the given name and attaches the container to it, setting the network alias // on that network to the given alias. +// Deprecated: use testcontainers.WithNetwork instead func WithNetwork(networkName string, alias string) testcontainers.CustomizeRequestOption { - return func(req *testcontainers.GenericContainerRequest) { - _, err := testcontainers.GenericNetwork(context.Background(), testcontainers.GenericNetworkRequest{ - NetworkRequest: testcontainers.NetworkRequest{ - Name: networkName, - }, - }) - if err != nil { - logger := req.Logger - if logger == nil { - logger = testcontainers.Logger - } - logger.Printf("Failed to create network '%s'. Container won't be attached to this network: %v", networkName, err) - return - } - - req.Networks = append(req.Networks, networkName) - - if req.NetworkAliases == nil { - req.NetworkAliases = make(map[string][]string) - } - req.NetworkAliases[networkName] = []string{alias} - } + return testcontainers.WithNetwork(networkName, alias) } // RunContainer creates an instance of the LocalStack container type, being possible to pass a custom request and options: