Skip to content

Commit c77be7f

Browse files
authoredNov 18, 2024
test(e2e): remove exec.Command calls (cloudnative-pg#53)
Switch from using exec.Command to using kind and docker as libraries, so tests won't depend on external binaries. Signed-off-by: Francesco Canovai <francesco.canovai@enterprisedb.com>
1 parent beef96e commit c77be7f

File tree

6 files changed

+163
-192
lines changed

6 files changed

+163
-192
lines changed
 

‎go.mod

+29-11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/cloudnative-pg/cnpg-i v0.0.0-20241109002750-8abd359df734
1212
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241030141108-7e59fc9f4797
1313
github.com/cloudnative-pg/machinery v0.0.0-20241105070525-042a028b767c
14+
github.com/docker/docker v27.3.1+incompatible
1415
github.com/onsi/ginkgo/v2 v2.21.0
1516
github.com/onsi/gomega v1.35.1
1617
github.com/spf13/cobra v1.8.1
@@ -23,11 +24,15 @@ require (
2324
k8s.io/client-go v0.31.2
2425
k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078
2526
sigs.k8s.io/controller-runtime v0.19.1
27+
sigs.k8s.io/kind v0.25.0
2628
sigs.k8s.io/kustomize/api v0.17.3
2729
sigs.k8s.io/kustomize/kyaml v0.17.2
2830
)
2931

3032
require (
33+
github.com/BurntSushi/toml v1.4.0 // indirect
34+
github.com/Microsoft/go-winio v0.4.14 // indirect
35+
github.com/alessio/shellescape v1.4.2 // indirect
3136
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
3237
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
3338
github.com/beorn7/perks v1.0.1 // indirect
@@ -36,7 +41,11 @@ require (
3641
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
3742
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3843
github.com/cloudnative-pg/api v0.0.0-20241004125129-98baa9f4957b // indirect
44+
github.com/containerd/log v0.1.0 // indirect
3945
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
46+
github.com/distribution/reference v0.6.0 // indirect
47+
github.com/docker/go-connections v0.5.0 // indirect
48+
github.com/docker/go-units v0.5.0 // indirect
4049
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
4150
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
4251
github.com/felixge/httpsnoop v1.0.4 // indirect
@@ -58,11 +67,12 @@ require (
5867
github.com/google/go-cmp v0.6.0 // indirect
5968
github.com/google/gofuzz v1.2.0 // indirect
6069
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
70+
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect
6171
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
6272
github.com/google/uuid v1.6.0 // indirect
6373
github.com/gorilla/websocket v1.5.1 // indirect
6474
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
65-
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
75+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
6676
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
6777
github.com/imdario/mergo v0.3.16 // indirect
6878
github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -73,13 +83,19 @@ require (
7383
github.com/lib/pq v1.10.9 // indirect
7484
github.com/magiconair/properties v1.8.7 // indirect
7585
github.com/mailru/easyjson v0.7.7 // indirect
86+
github.com/mattn/go-isatty v0.0.20 // indirect
7687
github.com/mitchellh/mapstructure v1.5.0 // indirect
88+
github.com/moby/docker-image-spec v1.3.1 // indirect
7789
github.com/moby/spdystream v0.4.0 // indirect
7890
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
7991
github.com/modern-go/reflect2 v1.0.2 // indirect
8092
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
93+
github.com/morikuni/aec v1.0.0 // indirect
8194
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
8295
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
96+
github.com/opencontainers/go-digest v1.0.0 // indirect
97+
github.com/opencontainers/image-spec v1.1.0 // indirect
98+
github.com/pelletier/go-toml v1.9.5 // indirect
8399
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
84100
github.com/pkg/errors v0.9.1 // indirect
85101
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.78.1 // indirect
@@ -101,33 +117,35 @@ require (
101117
github.com/x448/float16 v0.8.4 // indirect
102118
github.com/xlab/treeprint v1.2.0 // indirect
103119
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
104-
go.opentelemetry.io/otel v1.29.0 // indirect
105-
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
120+
go.opentelemetry.io/otel v1.32.0 // indirect
121+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect
106122
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect
107-
go.opentelemetry.io/otel/metric v1.29.0 // indirect
108-
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
109-
go.opentelemetry.io/otel/trace v1.29.0 // indirect
123+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 // indirect
124+
go.opentelemetry.io/otel/metric v1.32.0 // indirect
125+
go.opentelemetry.io/otel/sdk v1.32.0 // indirect
126+
go.opentelemetry.io/otel/trace v1.32.0 // indirect
110127
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
111128
go.starlark.net v0.0.0-20240925182052-1207426daebd // indirect
112129
go.uber.org/multierr v1.11.0 // indirect
113130
go.uber.org/zap v1.27.0 // indirect
114131
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
115132
golang.org/x/net v0.30.0 // indirect
116133
golang.org/x/oauth2 v0.23.0 // indirect
117-
golang.org/x/sync v0.8.0 // indirect
118-
golang.org/x/sys v0.26.0 // indirect
134+
golang.org/x/sync v0.9.0 // indirect
135+
golang.org/x/sys v0.27.0 // indirect
119136
golang.org/x/term v0.25.0 // indirect
120-
golang.org/x/text v0.19.0 // indirect
137+
golang.org/x/text v0.20.0 // indirect
121138
golang.org/x/time v0.7.0 // indirect
122139
golang.org/x/tools v0.26.0 // indirect
123140
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
124-
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
125-
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
141+
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect
142+
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
126143
google.golang.org/protobuf v1.35.1 // indirect
127144
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
128145
gopkg.in/inf.v0 v0.9.1 // indirect
129146
gopkg.in/ini.v1 v1.67.0 // indirect
130147
gopkg.in/yaml.v2 v2.4.0 // indirect
148+
gotest.tools/v3 v3.5.1 // indirect
131149
k8s.io/apiserver v0.31.2 // indirect
132150
k8s.io/component-base v0.31.2 // indirect
133151
k8s.io/klog/v2 v2.130.1 // indirect

‎go.sum

+74-24
Large diffs are not rendered by default.

‎scripts/setup-kind.sh

Whitespace-only changes.

‎test/e2e/internal/e2etestenv/main.go

+6-8
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"sigs.k8s.io/controller-runtime/pkg/client"
2626
"sigs.k8s.io/controller-runtime/pkg/client/config"
27+
"sigs.k8s.io/kind/pkg/cluster"
2728

2829
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/certmanager"
2930
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/cloudnativepg"
@@ -152,7 +153,7 @@ func Setup(ctx context.Context, opts ...SetupOption) (client.Client, error) {
152153
opt(&options)
153154
}
154155

155-
if err := setupKind(options); err != nil {
156+
if err := setupKind(ctx, options); err != nil {
156157
return nil, err
157158
}
158159

@@ -239,16 +240,13 @@ func getClient() (client.Client, error) {
239240
return cl, nil
240241
}
241242

242-
func setupKind(options SetupOptions) error {
243+
func setupKind(ctx context.Context, options SetupOptions) error {
243244
// This function sets up the environment for the e2e tests
244245
// by creating the cluster and installing the necessary
245246
// components.
246-
if err := kind.EnsureVersion(options.KindVersion); err != nil {
247-
return fmt.Errorf("failed to ensure Kind kindVersion: %w", err)
248-
}
249-
250247
expectedClusterName := kindClusterName(options.KindClusterNamePrefix, options.K8sVersion)
251-
clusterIsRunning, err := kind.IsClusterRunning(expectedClusterName)
248+
provider := cluster.NewProvider()
249+
clusterIsRunning, err := kind.IsClusterRunning(provider, expectedClusterName)
252250
if err != nil {
253251
return fmt.Errorf("failed to check if Kind cluster is running: %w", err)
254252
}
@@ -258,7 +256,7 @@ func setupKind(options SetupOptions) error {
258256
kind.WithConfigFile(kindConfigFile),
259257
kind.WithNetworks(options.KindAdditionalNetworks),
260258
}
261-
if err := kind.CreateCluster(expectedClusterName, kindOpts...); err != nil {
259+
if err := kind.CreateCluster(ctx, provider, expectedClusterName, kindOpts...); err != nil {
262260
return fmt.Errorf("failed to create Kind cluster: %w", err)
263261
}
264262
}

‎test/e2e/internal/kind/cluster.go

+54-33
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,25 @@ limitations under the License.
1717
package kind
1818

1919
import (
20+
"context"
2021
"fmt"
21-
"os"
2222
"os/exec"
23-
"strings"
23+
24+
"github.com/docker/docker/api/types/container"
25+
"github.com/docker/docker/api/types/strslice"
26+
"github.com/docker/docker/client"
27+
"sigs.k8s.io/kind/pkg/cluster"
28+
"sigs.k8s.io/kind/pkg/cluster/nodes"
2429
)
2530

2631
// IsClusterRunning checks if a Kind cluster with the given name is running
27-
func IsClusterRunning(clusterName string) (bool, error) {
28-
cmd := exec.Command(Kind, "get", "clusters")
29-
output, err := cmd.CombinedOutput()
32+
func IsClusterRunning(provider *cluster.Provider, clusterName string) (bool, error) {
33+
clusters, err := provider.List()
3034
if err != nil {
31-
return false, fmt.Errorf("failed to get Kind clusters: %w, output: %s", err, string(output))
35+
return false, fmt.Errorf("failed to list Kind clusters: %w", err)
3236
}
33-
34-
clusters := strings.Split(strings.TrimSpace(string(output)), "\n")
35-
for _, cluster := range clusters {
36-
if cluster == clusterName {
37+
for _, c := range clusters {
38+
if c == clusterName {
3739
return true, nil
3840
}
3941
}
@@ -73,61 +75,80 @@ func WithNetworks(networks []string) CreateClusterOption {
7375
}
7476

7577
// CreateCluster creates a Kind cluster with the given name
76-
func CreateCluster(name string, opts ...CreateClusterOption) error {
78+
func CreateCluster(ctx context.Context, provider *cluster.Provider, name string, opts ...CreateClusterOption) error {
7779
options := &CreateClusterOptions{}
7880
for _, opt := range opts {
7981
opt(options)
8082
}
8183

82-
args := []string{"create", "cluster", "--name", name}
84+
createOpts := []cluster.CreateOption{
85+
cluster.CreateWithRetain(true),
86+
cluster.CreateWithDisplayUsage(true),
87+
cluster.CreateWithDisplaySalutation(true),
88+
}
8389
if options.ConfigFile != "" {
84-
args = append(args, "--config", options.ConfigFile)
90+
createOpts = append(createOpts, cluster.CreateWithConfigFile(options.ConfigFile))
8591
}
8692
if options.K8sVersion != "" {
87-
args = append(args, "--image", fmt.Sprintf("kindest/node:%s", options.K8sVersion))
93+
createOpts = append(createOpts, cluster.CreateWithNodeImage(fmt.Sprintf("kindest/node:%s", options.K8sVersion)))
94+
}
95+
err := provider.Create(name, createOpts...)
96+
if err != nil {
97+
return fmt.Errorf("kind cluster creation failed: %w", err)
8898
}
8999

90-
cmd := exec.Command(Kind, args...) // #nosec
91-
cmd.Dir, _ = os.Getwd()
92-
output, err := cmd.CombinedOutput()
100+
// Initialize Docker client
101+
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
93102
if err != nil {
94-
return fmt.Errorf("'kind create cluster' failed: %w, output: %s", err, string(output))
103+
return fmt.Errorf("failed to create Docker client: %w", err)
95104
}
96105

97106
// Since a cluster can mount additional certificates, we need to make sure they are
98107
// usable by the nodes in the cluster.
99-
nodes, err := getNodes(name)
108+
nodeList, err := getNodes(provider, name)
100109
if err != nil {
101110
return err
102111
}
103-
for _, node := range nodes {
104-
cmd = exec.Command("docker", "exec", node, "update-ca-certificates") // #nosec
105-
output, err = cmd.CombinedOutput()
112+
for _, node := range nodeList {
113+
cmd := exec.Command("docker", "exec", node.String(), "update-ca-certificates") // #nosec
114+
output, err := cmd.CombinedOutput()
106115
if err != nil {
107116
return fmt.Errorf("failed to update CA certificates in node %s: %w, output: %s", node, err, string(output))
108117
}
118+
119+
execConfig := container.ExecOptions{
120+
Cmd: strslice.StrSlice([]string{"update-ca-certificates"}),
121+
AttachStdout: true,
122+
AttachStderr: true,
123+
}
124+
execID, err := cli.ContainerExecCreate(ctx, node.String(), execConfig)
125+
if err != nil {
126+
return fmt.Errorf("failed to create exec instance in node %s: %w", node.String(), err)
127+
}
128+
129+
err = cli.ContainerExecStart(ctx, execID.ID, container.ExecStartOptions{})
130+
if err != nil {
131+
return fmt.Errorf("failed to start exec instance in node %s: %w", node.String(), err)
132+
}
109133
}
110134

111-
for _, network := range options.Networks {
112-
for _, node := range nodes {
113-
cmd = exec.Command("docker", "network", "connect", network, node) // #nosec
114-
output, err = cmd.CombinedOutput()
135+
for _, netw := range options.Networks {
136+
for _, node := range nodeList {
137+
err := cli.NetworkConnect(ctx, netw, node.String(), nil)
115138
if err != nil {
116-
return fmt.Errorf("failed to connect node %s to network %s: %w, output: %s", node, network, err,
117-
string(output))
139+
return fmt.Errorf("failed to connect node %s to network %s: %w", node.String(), netw, err)
118140
}
119141
}
120142
}
121143

122144
return nil
123145
}
124146

125-
func getNodes(clusterName string) ([]string, error) {
126-
cmd := exec.Command(Kind, "get", "nodes", "--name", clusterName)
127-
output, err := cmd.CombinedOutput()
147+
func getNodes(provider *cluster.Provider, clusterName string) ([]nodes.Node, error) {
148+
nodeList, err := provider.ListNodes(clusterName)
128149
if err != nil {
129-
return nil, fmt.Errorf("failed to get Kind nodes: %w, output: %s", err, string(output))
150+
return nil, fmt.Errorf("failed to get Kind nodes: %w", err)
130151
}
131152

132-
return strings.Split(strings.TrimSpace(string(output)), "\n"), nil
153+
return nodeList, nil
133154
}

‎test/e2e/internal/kind/kind.go

-116
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.