Skip to content

Commit b395520

Browse files
xBlaz3kxmdelapenya
andauthored
feat(influxdb): support for influxdbv2 (#3072)
* feat: influxdb v2 support * chore: consistent import --------- Co-authored-by: Manuel de la Peña <mdelapenya@gmail.com>
1 parent 66401ba commit b395520

6 files changed

Lines changed: 647 additions & 5 deletions

File tree

docs/modules/influxdb.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Since testcontainers-go <a href="https://github.com/testcontainers/testcontainer
44

55
## Introduction
66

7-
A testcontainers module for InfluxDB. This module supports v1.x of InfluxDB.
7+
A testcontainers module for InfluxDB V1 and V2.
88

99
## Adding this module to your project dependencies
1010

@@ -16,8 +16,11 @@ go get github.com/testcontainers/testcontainers-go/modules/influxdb
1616

1717
## Usage example
1818

19+
### InfluxDB
20+
1921
<!--codeinclude-->
20-
[Creating an InfluxDB container](../../modules/influxdb/examples_test.go) inside_block:runInfluxContainer
22+
[Creating an InfluxDB V1 container](../../modules/influxdb/examples_test.go) inside_block:runInfluxContainer
23+
[Creating an InfluxDB V2 container](../../modules/influxdb/examples_test.go) inside_block:runInfluxV2Container
2124
<!--/codeinclude-->
2225

2326
## Module Reference
@@ -54,7 +57,7 @@ Use the second argument in the `Run` function to set a valid Docker image.
5457
In example: `Run(context.Background(), "influxdb:1.8.0")`.
5558

5659
!!!info
57-
Note that `influxdb:latest` will get you a version 2 image which is not supported by this module.
60+
Note that `influxdb:latest` will pull a version 2 image.
5861

5962
{% include "../features/common_functional_options.md" %}
6063

@@ -63,6 +66,20 @@ In example: `Run(context.Background(), "influxdb:1.8.0")`.
6366
By default, authentication is disabled and no credentials are needed to use the Influx API against the test container.
6467
If you want to test with credentials, include the appropriate environment variables to do so.
6568

69+
#### Configuring InfluxDB V2
70+
71+
- Not available until the next release of testcontainers-go <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
72+
73+
When running the InfluxDB V2 image, you can override the default configuration by using options prefixed by `influxdb.WithV2`.
74+
The following options are available:
75+
76+
- `WithV2(org, bucket string)`: Configures organization and bucket name. This option is required to run the InfluxDB V2 image.
77+
- `WithV2Auth(org, bucket, username, password string)`: Sets the username and password for the initial user.
78+
- `WithV2SecretsAuth(org, bucket, usernameFile, passwordFile string)`: Sets the username and password file path.
79+
- `WithV2Retention(retention time.Duration)`: Sets the default bucket retention policy.
80+
- `WithV2AdminToken(token string)`: Sets the admin token for the initial user.
81+
- `WithV2SecretsAdminToken(tokenFile string)`: Sets the admin token file path.
82+
6683
#### Init Scripts
6784

6885
While the InfluxDB image will obey the `/docker-entrypoint-initdb.d` directory as is common, that directory does not

modules/influxdb/examples_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"log"
77

8+
influxclient2 "github.com/influxdata/influxdb-client-go/v2"
9+
810
"github.com/testcontainers/testcontainers-go"
911
"github.com/testcontainers/testcontainers-go/modules/influxdb"
1012
)
@@ -41,3 +43,61 @@ func ExampleRun() {
4143
// Output:
4244
// true
4345
}
46+
47+
func ExampleRun_v2() {
48+
// runInfluxV2Container {
49+
ctx := context.Background()
50+
51+
username := "username"
52+
password := "password"
53+
org := "org"
54+
bucket := "bucket"
55+
token := "influxdbv2token"
56+
57+
influxdbContainer, err := influxdb.Run(ctx, "influxdb:2.7.11",
58+
influxdb.WithV2Auth(org, bucket, username, password), // Set the username and password
59+
influxdb.WithV2AdminToken(token), // Set the admin token
60+
)
61+
defer func() {
62+
if err := testcontainers.TerminateContainer(influxdbContainer); err != nil {
63+
log.Printf("failed to terminate container: %s", err)
64+
}
65+
}()
66+
if err != nil {
67+
log.Printf("failed to start container: %s", err)
68+
return
69+
}
70+
// }
71+
72+
state, err := influxdbContainer.State(ctx)
73+
if err != nil {
74+
log.Printf("failed to get container state: %s", err)
75+
return
76+
}
77+
78+
fmt.Println(state.Running)
79+
80+
// Query the InfluxDB API to verify the setup
81+
url, err := influxdbContainer.ConnectionUrl(ctx)
82+
if err != nil {
83+
log.Printf("failed to get host: %s", err)
84+
return
85+
}
86+
87+
// Initialize a new InfluxDB client
88+
client := influxclient2.NewClientWithOptions(url, token, influxclient2.DefaultOptions())
89+
defer client.Close()
90+
91+
// Get the bucket
92+
influxBucket, err := client.BucketsAPI().FindBucketByName(ctx, bucket)
93+
if err != nil {
94+
log.Printf("failed to get bucket: %s", err)
95+
return
96+
}
97+
98+
fmt.Println(influxBucket.Name)
99+
100+
// Output:
101+
// true
102+
// bucket
103+
}

modules/influxdb/go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.23.0
55
toolchain go1.23.6
66

77
require (
8+
github.com/influxdata/influxdb-client-go/v2 v2.14.0
89
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
910
github.com/stretchr/testify v1.10.0
1011
github.com/testcontainers/testcontainers-go v0.36.0
@@ -14,6 +15,7 @@ require (
1415
dario.cat/mergo v1.0.1 // indirect
1516
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
1617
github.com/Microsoft/go-winio v0.6.2 // indirect
18+
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
1719
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
1820
github.com/containerd/log v0.1.0 // indirect
1921
github.com/containerd/platforms v0.2.1 // indirect
@@ -30,6 +32,7 @@ require (
3032
github.com/go-ole/go-ole v1.2.6 // indirect
3133
github.com/gogo/protobuf v1.3.2 // indirect
3234
github.com/google/uuid v1.6.0 // indirect
35+
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
3336
github.com/klauspost/compress v1.17.4 // indirect
3437
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
3538
github.com/magiconair/properties v1.8.9 // indirect
@@ -40,6 +43,7 @@ require (
4043
github.com/moby/sys/userns v0.1.0 // indirect
4144
github.com/moby/term v0.5.0 // indirect
4245
github.com/morikuni/aec v1.0.0 // indirect
46+
github.com/oapi-codegen/runtime v1.0.0 // indirect
4347
github.com/opencontainers/go-digest v1.0.0 // indirect
4448
github.com/opencontainers/image-spec v1.1.1 // indirect
4549
github.com/pkg/errors v0.9.1 // indirect

modules/influxdb/go.sum

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl
66
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
77
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
88
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
9+
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
10+
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
11+
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
12+
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
913
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
1014
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
1115
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
@@ -47,8 +51,13 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
4751
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
4852
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
4953
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
54+
github.com/influxdata/influxdb-client-go/v2 v2.14.0 h1:AjbBfJuq+QoaXNcrova8smSjwJdUHnwvfjMF71M1iI4=
55+
github.com/influxdata/influxdb-client-go/v2 v2.14.0/go.mod h1:Ahpm3QXKMJslpXl3IftVLVezreAUtBOTZssDrjZEFHI=
5056
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs=
5157
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
58+
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
59+
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
60+
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
5261
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
5362
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
5463
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
@@ -75,6 +84,8 @@ github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
7584
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
7685
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
7786
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
87+
github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo=
88+
github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A=
7889
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
7990
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
8091
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
@@ -91,9 +102,11 @@ github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0Zqm
91102
github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI=
92103
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
93104
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
105+
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
94106
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
95107
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
96108
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
109+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
97110
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
98111
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
99112
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
@@ -156,8 +169,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
156169
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
157170
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
158171
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
159-
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
160-
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
172+
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
173+
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
161174
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
162175
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
163176
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=

modules/influxdb/influxdb.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package influxdb
33
import (
44
"context"
55
"encoding/json"
6+
"errors"
67
"fmt"
78
"io"
89
"path"
10+
"time"
911

1012
"github.com/testcontainers/testcontainers-go"
1113
"github.com/testcontainers/testcontainers-go/wait"
@@ -120,6 +122,142 @@ func WithConfigFile(configFile string) testcontainers.CustomizeRequestOption {
120122
}
121123
}
122124

125+
// withV2 configures the influxdb container to be compatible with InfluxDB v2
126+
func withV2(req *testcontainers.GenericContainerRequest, org, bucket string) error {
127+
if org == "" {
128+
return errors.New("organization name is required")
129+
}
130+
131+
if bucket == "" {
132+
return errors.New("bucket name is required")
133+
}
134+
135+
req.Env["DOCKER_INFLUXDB_INIT_ORG"] = org
136+
req.Env["DOCKER_INFLUXDB_INIT_BUCKET"] = bucket
137+
req.Env["DOCKER_INFLUXDB_INIT_MODE"] = "setup" // Always setup, we wont be migrating from v1 to v2
138+
return nil
139+
}
140+
141+
// WithV2 configures the influxdb container to be compatible with InfluxDB v2
142+
func WithV2(org, bucket string) testcontainers.CustomizeRequestOption {
143+
return func(req *testcontainers.GenericContainerRequest) error {
144+
err := withV2(req, org, bucket)
145+
if err != nil {
146+
return err
147+
}
148+
149+
return nil
150+
}
151+
}
152+
153+
const dockerSecretPath = "/run/secrets"
154+
155+
func secretsPath(path string) string {
156+
return dockerSecretPath + "/" + path
157+
}
158+
159+
// WithV2Auth configures the influxdb container to be compatible with InfluxDB v2 and sets the username and password
160+
// for the initial user.
161+
func WithV2Auth(org, bucket, username, password string) testcontainers.CustomizeRequestOption {
162+
return func(req *testcontainers.GenericContainerRequest) error {
163+
if username == "" {
164+
return errors.New("username is required")
165+
}
166+
167+
if password == "" {
168+
return errors.New("password is required")
169+
}
170+
171+
err := withV2(req, org, bucket)
172+
if err != nil {
173+
return err
174+
}
175+
176+
if req.Env["DOCKER_INFLUXDB_INIT_USERNAME_FILE"] != "" ||
177+
req.Env["DOCKER_INFLUXDB_INIT_PASSWORD_FILE"] != "" {
178+
return errors.New("username and password file already set, use either WithV2Auth or WithV2SecretsAuth")
179+
}
180+
181+
req.Env["DOCKER_INFLUXDB_INIT_USERNAME"] = username
182+
req.Env["DOCKER_INFLUXDB_INIT_PASSWORD"] = password
183+
return nil
184+
}
185+
}
186+
187+
// WithV2SecretsAuth configures the container to be compatible with InfluxDB v2 and sets the username and password file path
188+
func WithV2SecretsAuth(org, bucket, usernameFile, passwordFile string) testcontainers.CustomizeRequestOption {
189+
return func(req *testcontainers.GenericContainerRequest) error {
190+
if usernameFile == "" {
191+
return errors.New("username file is required")
192+
}
193+
194+
if passwordFile == "" {
195+
return errors.New("password file is required")
196+
}
197+
198+
if req.Env["DOCKER_INFLUXDB_INIT_USERNAME"] != "" ||
199+
req.Env["DOCKER_INFLUXDB_INIT_PASSWORD"] != "" {
200+
return errors.New("username and password already set, use either WithV2Auth or WithV2SecretsAuth")
201+
}
202+
203+
err := withV2(req, org, bucket)
204+
if err != nil {
205+
return err
206+
}
207+
208+
req.Env["DOCKER_INFLUXDB_INIT_USERNAME_FILE"] = secretsPath(usernameFile)
209+
req.Env["DOCKER_INFLUXDB_INIT_PASSWORD_FILE"] = secretsPath(passwordFile)
210+
return nil
211+
}
212+
}
213+
214+
// WithV2Retention configures the default bucket's retention
215+
func WithV2Retention(retention time.Duration) testcontainers.CustomizeRequestOption {
216+
return func(req *testcontainers.GenericContainerRequest) error {
217+
if retention == 0 {
218+
return errors.New("retention is required")
219+
}
220+
221+
req.Env["DOCKER_INFLUXDB_INIT_RETENTION"] = retention.String()
222+
223+
return nil
224+
}
225+
}
226+
227+
// WithV2AdminToken sets the admin token for the influxdb container
228+
func WithV2AdminToken(token string) testcontainers.CustomizeRequestOption {
229+
return func(req *testcontainers.GenericContainerRequest) error {
230+
if token == "" {
231+
return errors.New("admin token is required")
232+
}
233+
234+
if req.Env["DOCKER_INFLUXDB_INIT_ADMIN_TOKEN_FILE"] != "" {
235+
return errors.New("admin token file already set, use either WithV2AdminToken or WithV2SecretsAdminToken")
236+
}
237+
238+
req.Env["DOCKER_INFLUXDB_INIT_ADMIN_TOKEN"] = token
239+
240+
return nil
241+
}
242+
}
243+
244+
// WithV2SecretsAdminToken sets the admin token for the influxdb container using a file
245+
func WithV2SecretsAdminToken(tokenFile string) testcontainers.CustomizeRequestOption {
246+
return func(req *testcontainers.GenericContainerRequest) error {
247+
if tokenFile == "" {
248+
return errors.New("admin token file is required")
249+
}
250+
251+
if req.Env["DOCKER_INFLUXDB_INIT_ADMIN_TOKEN"] != "" {
252+
return errors.New("admin token already set, use either WithV2AdminToken or WithV2SecretsAdminToken")
253+
}
254+
255+
req.Env["DOCKER_INFLUXDB_INIT_ADMIN_TOKEN_FILE"] = secretsPath(tokenFile)
256+
257+
return nil
258+
}
259+
}
260+
123261
// WithInitDb returns a request customizer that initialises the database using the file `docker-entrypoint-initdb.d`
124262
// located in `srcPath` directory.
125263
//

0 commit comments

Comments
 (0)