Skip to content

Commit f954f6d

Browse files
authored
feat: add etcd module (testcontainers#2788)
* chore: scaffolding for etcd module * feat: add etcd with cluster support * feat: support for AutoTLS * chore: add unit test for cmd * fix: remove non-existent module * chore: simplify removing auto-tls support * docs: remove old deprecated function * docs: document functions * docs: remove commented code * chore: more readable tests * chore: move logic to the functional option * chore: simplify passing current node opts * fix: return the parent node when creating the child nodes * chore: move to constant * chore: use zero values * fix: typo after wrong copy&paste * chore: remove must methods * chore: use private fields in the container * chore: use private fields in the options struct * chore: simplify public API * chore: make constants private * fix: lint * chore: rename field to childNodes * docs: enrich container comments * fix: assert on the right node * chore: bump dockercfg * feat: implement termination of the cluster * chore: use require.Zero * chore: proper test name * chore: preallocate slice * chore: do not allow single-node clusters * fix: join errors on terminate cluster * fix: check parent container is terminated * chore: extract to function * fix: check if container is not nil * chor: do not orphan the network * chore: simplify * docs: fix comment * chore: wrap errors in endpoint functions * Revert "chore: wrap errors in endpoint functions" This reverts commit 1c4361b. * chore: simplify eval * fix: not needed * chore: simplify container initialisation * chore: simplify even more
1 parent 7a1419d commit f954f6d

File tree

14 files changed

+1155
-2
lines changed

14 files changed

+1155
-2
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ jobs:
9494
matrix:
9595
go-version: [1.22.x, 1.x]
9696
platform: [ubuntu-latest]
97-
module: [artemis, azurite, cassandra, chroma, clickhouse, cockroachdb, compose, consul, couchbase, databend, dolt, dynamodb, elasticsearch, gcloud, grafana-lgtm, inbucket, influxdb, k3s, k6, kafka, localstack, mariadb, milvus, minio, mockserver, mongodb, mssql, mysql, nats, neo4j, ollama, openfga, openldap, opensearch, postgres, pulsar, qdrant, rabbitmq, redis, redpanda, registry, surrealdb, valkey, vault, vearch, weaviate]
97+
module: [artemis, azurite, cassandra, chroma, clickhouse, cockroachdb, compose, consul, couchbase, databend, dolt, dynamodb, elasticsearch, etcd, gcloud, grafana-lgtm, inbucket, influxdb, k3s, k6, kafka, localstack, mariadb, milvus, minio, mockserver, mongodb, mssql, mysql, nats, neo4j, ollama, openfga, openldap, opensearch, postgres, pulsar, qdrant, rabbitmq, redis, redpanda, registry, surrealdb, valkey, vault, vearch, weaviate]
9898
uses: ./.github/workflows/ci-test-go.yml
9999
with:
100100
go-version: ${{ matrix.go-version }}

.vscode/.testcontainers-go.code-workspace

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@
6565
"name": "module / elasticsearch",
6666
"path": "../modules/elasticsearch"
6767
},
68+
{
69+
"name": "module / etcd",
70+
"path": "../modules/etcd"
71+
},
6872
{
6973
"name": "module / gcloud",
7074
"path": "../modules/gcloud"

docs/modules/etcd.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# etcd
2+
3+
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>
4+
5+
## Introduction
6+
7+
The Testcontainers module for etcd.
8+
9+
## Adding this module to your project dependencies
10+
11+
Please run the following command to add the etcd module to your Go dependencies:
12+
13+
```
14+
go get github.com/testcontainers/testcontainers-go/modules/etcd
15+
```
16+
17+
## Usage example
18+
19+
<!--codeinclude-->
20+
[Creating a etcd container](../../modules/etcd/examples_test.go) inside_block:runetcdContainer
21+
<!--/codeinclude-->
22+
23+
## Module Reference
24+
25+
### Run function
26+
27+
- 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>
28+
29+
The etcd module exposes one entrypoint function to create the etcd container, and this function receives three parameters:
30+
31+
```golang
32+
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*etcdContainer, error)
33+
```
34+
35+
- `context.Context`, the Go context.
36+
- `string`, the Docker image to use.
37+
- `testcontainers.ContainerCustomizer`, a variadic argument for passing options.
38+
39+
### Container Options
40+
41+
When starting the etcd container, you can pass options in a variadic way to configure it.
42+
43+
#### Image
44+
45+
If you need to set a different etcd Docker image, you can set a valid Docker image as the second argument in the `Run` function.
46+
E.g. `Run(context.Background(), "bitnami/etcd:latest")`.
47+
48+
{% include "../features/common_functional_options.md" %}
49+
50+
#### WithAdditionalArgs
51+
52+
- 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>
53+
54+
You can pass additional arguments to the etcd container by using the `WithAdditionalArgs` option. The arguments are passed to the CMD of the etcd container.
55+
56+
#### WithDataDir
57+
58+
- 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>
59+
60+
You can set the data directory for the etcd container by using the `WithDataDir` boolean option. The data directory where the etcd data is stored is `/data.etcd`.
61+
62+
#### WithNodes
63+
64+
- 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>
65+
66+
You can set the number of nodes for the etcd cluster by using the `WithNodes` option, passing the node names for each of the nodes. Single-node clusters are not allowed,
67+
for that reason the functional option receives three string arguments: the first node, the second node, and a variadic argument for the rest of the nodes.
68+
The module starts a container for each node, having the first node a reference to the other nodes. E.g. `WithNodes("etcd-1", "etcd-2")`, `WithNodes("etcd-1", "etcd-2", "etcd-3")` and so on.
69+
70+
The module creates a Docker network for the etcd cluster, and the nodes are connected to this network, so that they can communicate with each other through the network.
71+
72+
#### WithClusterToken
73+
74+
- 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>
75+
76+
Sets the cluster token for the etcd cluster. The cluster token is used to identify the etcd cluster. The default value is `mys3cr3ttok3n`.
77+
The etcd container holds a reference to the cluster token, so you can use it with e.g. `ctr.ClusterToken`.
78+
79+
### Container Methods
80+
81+
- 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>
82+
83+
The etcd container exposes the following methods:
84+
85+
#### ClientEndpoint
86+
87+
- 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>
88+
89+
Returns the client endpoint for the etcd container and an error, if any. In the case of a cluster, it returns the client endpoint for the first node.
90+
91+
#### PeerEndpoint
92+
93+
- 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>
94+
95+
Returns the peer endpoint for the etcd container and an error, if any. In the case of a cluster, it returns the peer endpoint for the first node.

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ nav:
7878
- modules/dolt.md
7979
- modules/dynamodb.md
8080
- modules/elasticsearch.md
81+
- modules/etcd.md
8182
- modules/gcloud.md
8283
- modules/grafana-lgtm.md
8384
- modules/inbucket.md

modules/etcd/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
include ../../commons-test.mk
2+
3+
.PHONY: test
4+
test:
5+
$(MAKE) test-etcd

modules/etcd/cmd_test.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package etcd
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func Test_configureCMD(t *testing.T) {
10+
t.Run("default", func(t *testing.T) {
11+
got := configureCMD(options{})
12+
want := []string{"etcd", "--name=default"}
13+
require.Equal(t, want, got)
14+
})
15+
16+
t.Run("with-node", func(t *testing.T) {
17+
got := configureCMD(options{
18+
nodeNames: []string{"node1"},
19+
})
20+
want := []string{
21+
"etcd",
22+
"--name=node1",
23+
"--initial-advertise-peer-urls=http://node1:2380",
24+
"--advertise-client-urls=http://node1:2379",
25+
"--listen-peer-urls=http://0.0.0.0:2380",
26+
"--listen-client-urls=http://0.0.0.0:2379",
27+
"--initial-cluster-state=new",
28+
"--initial-cluster=node1=http://node1:2380",
29+
}
30+
require.Equal(t, want, got)
31+
})
32+
33+
t.Run("with-node-datadir", func(t *testing.T) {
34+
got := configureCMD(options{
35+
nodeNames: []string{"node1"},
36+
mountDataDir: true,
37+
})
38+
want := []string{
39+
"etcd",
40+
"--name=node1",
41+
"--initial-advertise-peer-urls=http://node1:2380",
42+
"--advertise-client-urls=http://node1:2379",
43+
"--listen-peer-urls=http://0.0.0.0:2380",
44+
"--listen-client-urls=http://0.0.0.0:2379",
45+
"--initial-cluster-state=new",
46+
"--initial-cluster=node1=http://node1:2380",
47+
"--data-dir=/data.etcd",
48+
}
49+
require.Equal(t, want, got)
50+
})
51+
52+
t.Run("with-node-datadir-additional-args", func(t *testing.T) {
53+
got := configureCMD(options{
54+
nodeNames: []string{"node1"},
55+
mountDataDir: true,
56+
additionalArgs: []string{"--auto-compaction-retention=1"},
57+
})
58+
want := []string{
59+
"etcd",
60+
"--name=node1",
61+
"--initial-advertise-peer-urls=http://node1:2380",
62+
"--advertise-client-urls=http://node1:2379",
63+
"--listen-peer-urls=http://0.0.0.0:2380",
64+
"--listen-client-urls=http://0.0.0.0:2379",
65+
"--initial-cluster-state=new",
66+
"--initial-cluster=node1=http://node1:2380",
67+
"--data-dir=/data.etcd",
68+
"--auto-compaction-retention=1",
69+
}
70+
require.Equal(t, want, got)
71+
})
72+
73+
t.Run("with-cluster", func(t *testing.T) {
74+
got := configureCMD(options{
75+
nodeNames: []string{"node1", "node2"},
76+
})
77+
want := []string{
78+
"etcd",
79+
"--name=node1",
80+
"--initial-advertise-peer-urls=http://node1:2380",
81+
"--advertise-client-urls=http://node1:2379",
82+
"--listen-peer-urls=http://0.0.0.0:2380",
83+
"--listen-client-urls=http://0.0.0.0:2379",
84+
"--initial-cluster-state=new",
85+
"--initial-cluster=node1=http://node1:2380,node2=http://node2:2380",
86+
}
87+
require.Equal(t, want, got)
88+
})
89+
90+
t.Run("with-cluster-token", func(t *testing.T) {
91+
got := configureCMD(options{
92+
nodeNames: []string{"node1", "node2"},
93+
clusterToken: "token",
94+
})
95+
want := []string{
96+
"etcd",
97+
"--name=node1",
98+
"--initial-advertise-peer-urls=http://node1:2380",
99+
"--advertise-client-urls=http://node1:2379",
100+
"--listen-peer-urls=http://0.0.0.0:2380",
101+
"--listen-client-urls=http://0.0.0.0:2379",
102+
"--initial-cluster-state=new",
103+
"--initial-cluster=node1=http://node1:2380,node2=http://node2:2380",
104+
"--initial-cluster-token=token",
105+
}
106+
require.Equal(t, want, got)
107+
})
108+
}

0 commit comments

Comments
 (0)