From 754c792e6d563d7b682567af179e99ddb5fd7753 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Fri, 17 Feb 2023 14:09:39 +0300 Subject: [PATCH 01/40] create couchbase module --- .github/dependabot.yml | 30 ++- .github/workflows/module-couchbase.yml | 46 ++++ docs/modules/couchbase.md | 9 + mkdocs.yml | 1 + modules/couchbase/Makefile | 5 + modules/couchbase/couchbase.go | 28 +++ modules/couchbase/couchbase_test.go | 24 ++ modules/couchbase/go.mod | 54 +++++ modules/couchbase/go.sum | 290 +++++++++++++++++++++++++ modules/couchbase/tools/tools.go | 11 + 10 files changed, 486 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/module-couchbase.yml create mode 100644 docs/modules/couchbase.md create mode 100644 modules/couchbase/Makefile create mode 100644 modules/couchbase/couchbase.go create mode 100644 modules/couchbase/couchbase_test.go create mode 100644 modules/couchbase/go.mod create mode 100644 modules/couchbase/go.sum create mode 100644 modules/couchbase/tools/tools.go diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 92f9ee5cf1..4116372f22 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,18 +12,6 @@ updates: interval: weekly open-pull-requests-limit: 3 rebase-strategy: disabled - - package-ecosystem: gomod - directory: /modules/compose - schedule: - interval: weekly - open-pull-requests-limit: 3 - rebase-strategy: disabled - - package-ecosystem: gomod - directory: /modules/localstack - schedule: - interval: weekly - open-pull-requests-limit: 3 - rebase-strategy: disabled - package-ecosystem: gomod directory: /examples/bigtable schedule: @@ -108,3 +96,21 @@ updates: interval: weekly open-pull-requests-limit: 3 rebase-strategy: disabled + - package-ecosystem: gomod + directory: /modulegen + schedule: + interval: weekly + open-pull-requests-limit: 3 + rebase-strategy: disabled + - package-ecosystem: gomod + directory: /modules/couchbase + schedule: + interval: weekly + open-pull-requests-limit: 3 + rebase-strategy: disabled + - package-ecosystem: gomod + directory: /modules/localstack + schedule: + interval: weekly + open-pull-requests-limit: 3 + rebase-strategy: disabled diff --git a/.github/workflows/module-couchbase.yml b/.github/workflows/module-couchbase.yml new file mode 100644 index 0000000000..3d85462e04 --- /dev/null +++ b/.github/workflows/module-couchbase.yml @@ -0,0 +1,46 @@ +name: Couchbase module pipeline + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + cancel-in-progress: true + +jobs: + test-couchbase: + strategy: + matrix: + go-version: [1.18.x, 1.x] + runs-on: "ubuntu-latest" + steps: + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.go-version }} + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v3 + + - name: modVerify + working-directory: ./examples/couchbase + run: go mod verify + + - name: modTidy + working-directory: ./examples/couchbase + run: make tools-tidy + + - name: gotestsum + working-directory: ./examples/couchbase + run: make test-unit + + - name: Run checker + run: | + ./scripts/check_environment.sh + + - name: Test Summary + uses: test-summary/action@4ee9ece4bca777a38f05c8fc578ac2007fe266f7 + with: + paths: "**/TEST-couchbase*.xml" + if: always() diff --git a/docs/modules/couchbase.md b/docs/modules/couchbase.md new file mode 100644 index 0000000000..61513356f8 --- /dev/null +++ b/docs/modules/couchbase.md @@ -0,0 +1,9 @@ +# Couchbase + + +[Creating a Couchbase container](../../examples/couchbase/couchbase.go) + + + +[Test for a Couchbase container](../../examples/couchbase/couchbase_test.go) + diff --git a/mkdocs.yml b/mkdocs.yml index 39c544d3e2..df02854ec0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -48,6 +48,7 @@ nav: - SQL: features/wait/sql.md - Modules: - modules/index.md + - modules/couchbase.md - modules/localstack.md - Examples: - examples/index.md diff --git a/modules/couchbase/Makefile b/modules/couchbase/Makefile new file mode 100644 index 0000000000..ed6c537a0d --- /dev/null +++ b/modules/couchbase/Makefile @@ -0,0 +1,5 @@ +include ../../commons-test.mk + +.PHONY: test +test: + $(MAKE) test-couchbase diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go new file mode 100644 index 0000000000..8a983f0b65 --- /dev/null +++ b/modules/couchbase/couchbase.go @@ -0,0 +1,28 @@ +package couchbase + +import ( + "context" + + "github.com/testcontainers/testcontainers-go" +) + +// CouchbaseContainer represents the Couchbase container type used in the module +type CouchbaseContainer struct { + testcontainers.Container +} + +// StartContainer creates an instance of the Couchbase container type +func StartContainer(ctx context.Context) (*CouchbaseContainer, error) { + req := testcontainers.ContainerRequest{ + Image: "couchbase:6.5.1", + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + + return &CouchbaseContainer{Container: container}, nil +} diff --git a/modules/couchbase/couchbase_test.go b/modules/couchbase/couchbase_test.go new file mode 100644 index 0000000000..9951bb801e --- /dev/null +++ b/modules/couchbase/couchbase_test.go @@ -0,0 +1,24 @@ +package couchbase + +import ( + "context" + "testing" +) + +func TestCouchbase(t *testing.T) { + ctx := context.Background() + + container, err := StartContainer(ctx) + if err != nil { + t.Fatal(err) + } + + // Clean up the container after the test is complete + t.Cleanup(func() { + if err := container.Terminate(ctx); err != nil { + t.Fatalf("failed to terminate container: %s", err) + } + }) + + // perform assertions +} diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod new file mode 100644 index 0000000000..41ece3573d --- /dev/null +++ b/modules/couchbase/go.mod @@ -0,0 +1,54 @@ +module github.com/testcontainers/testcontainers-go/examples/couchbase + +go 1.18 + +require ( + github.com/testcontainers/testcontainers-go v0.18.0 + gotest.tools/gotestsum v1.9.0 +) + +require ( + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.5.2 // indirect + github.com/cenkalti/backoff/v4 v4.2.0 // indirect + github.com/containerd/containerd v1.6.17 // indirect + github.com/dnephin/pflag v1.0.7 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/docker/docker v23.0.0+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/klauspost/compress v1.15.9 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/moby/patternmatcher v0.5.0 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc2 // indirect + github.com/opencontainers/runc v1.1.3 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect + golang.org/x/tools v0.1.12 // indirect + google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect + google.golang.org/grpc v1.47.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect + gotest.tools/v3 v3.4.0 // indirect +) + +replace ( + github.com/docker/docker => github.com/docker/docker v20.10.3-0.20221013203545-33ab36d6b304+incompatible // 22.06 branch + github.com/testcontainers/testcontainers-go => ../.. +) diff --git a/modules/couchbase/go.sum b/modules/couchbase/go.sum new file mode 100644 index 0000000000..bf1e749f38 --- /dev/null +++ b/modules/couchbase/go.sum @@ -0,0 +1,290 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/hcsshim v0.9.6 h1:VwnDOgLeoi2du6dAznfmspNqTiwczvjv4K7NxuY9jsY= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.6.17 h1:XDnJIeJW0cLf6v7/+N+6L9kGrChHeXekZp2VHu6OpiY= +github.com/containerd/containerd v1.6.17/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= +github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v20.10.3-0.20221013203545-33ab36d6b304+incompatible h1:ieHXawdo9MXKnRkKuVWEfEN3PDQUqIjz/T8vMfIaHkM= +github.com/docker/docker v20.10.3-0.20221013203545-33ab36d6b304+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f h1:J/7hjLaHLD7epG0m6TBMGmp4NQ+ibBYLfeyJWdAIFLA= +github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f/go.mod h1:15ce4BGCFxt7I5NQKT+HV0yEDxmf6fSysfEDiVo3zFM= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= +github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad h1:kqrS+lhvaMHCxul6sKQvKJ8nAAhlVItmZV822hYFH/U= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gotest.tools/gotestsum v1.9.0 h1:Jbo/0k/sIOXIJu51IZxEAt27n77xspFEfL6SqKUR72A= +gotest.tools/gotestsum v1.9.0/go.mod h1:6JHCiN6TEjA7Kaz23q1bH0e2Dc3YJjDUZ0DmctFZf+w= +gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/modules/couchbase/tools/tools.go b/modules/couchbase/tools/tools.go new file mode 100644 index 0000000000..ea5b168ede --- /dev/null +++ b/modules/couchbase/tools/tools.go @@ -0,0 +1,11 @@ +//go:build tools +// +build tools + +// This package contains the tool dependencies of the Couchbase example. + +package tools + +import ( + // Register gotestsum for pinning version + _ "gotest.tools/gotestsum" +) From 46ef6c7185d19c4b4b1553bb737dbe56898fd869 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Fri, 17 Feb 2023 16:16:36 +0300 Subject: [PATCH 02/40] expose enabled service ports --- modules/couchbase/couchbase.go | 45 ++++++++++++++++++++++++++++++++-- modules/couchbase/options.go | 19 ++++++++++++++ modules/couchbase/service.go | 44 +++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 modules/couchbase/options.go create mode 100644 modules/couchbase/service.go diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index 8a983f0b65..e9f73bbe97 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -2,20 +2,53 @@ package couchbase import ( "context" - "github.com/testcontainers/testcontainers-go" ) +const ( + MGMT_PORT = "8091" + MGMT_SSL_PORT = "18091" + + VIEW_PORT = "8092" + VIEW_SSL_PORT = "18092" + + QUERY_PORT = "8093" + QUERY_SSL_PORT = "18093" + + SEARCH_PORT = "8094" + SEARCH_SSL_PORT = "18094" + + ANALYTICS_PORT = "8095" + ANALYTICS_SSL_PORT = "18095" + + EVENTING_PORT = "8096" + EVENTING_SSL_PORT = "18096" + + KV_PORT = "11210" + KV_SSL_PORT = "11207" +) + // CouchbaseContainer represents the Couchbase container type used in the module type CouchbaseContainer struct { testcontainers.Container } // StartContainer creates an instance of the Couchbase container type -func StartContainer(ctx context.Context) (*CouchbaseContainer, error) { +func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, error) { + config := &Config{ + enabledServices: []service{kv, query, search, index}, + } + + for _, opt := range opts { + opt(config) + } + req := testcontainers.ContainerRequest{ Image: "couchbase:6.5.1", } + + exposePorts(&req, config.enabledServices) + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: req, Started: true, @@ -26,3 +59,11 @@ func StartContainer(ctx context.Context) (*CouchbaseContainer, error) { return &CouchbaseContainer{Container: container}, nil } + +func exposePorts(req *testcontainers.ContainerRequest, enabledServices []service) { + req.ExposedPorts = append(req.ExposedPorts, MGMT_PORT, MGMT_SSL_PORT) + + for _, service := range enabledServices { + req.ExposedPorts = append(req.ExposedPorts, service.ports...) + } +} diff --git a/modules/couchbase/options.go b/modules/couchbase/options.go new file mode 100644 index 0000000000..c609af92b4 --- /dev/null +++ b/modules/couchbase/options.go @@ -0,0 +1,19 @@ +package couchbase + +type Option func(*Config) + +type Config struct { + enabledServices []service +} + +func WithEventingService() Option { + return func(c *Config) { + c.enabledServices = append(c.enabledServices, eventing) + } +} + +func WithAnalyticsService() Option { + return func(c *Config) { + c.enabledServices = append(c.enabledServices, analytics) + } +} diff --git a/modules/couchbase/service.go b/modules/couchbase/service.go new file mode 100644 index 0000000000..12a761191f --- /dev/null +++ b/modules/couchbase/service.go @@ -0,0 +1,44 @@ +package couchbase + +type service struct { + identifier string + minimumQuotaMb int + ports []string +} + +var ( + kv = service{ + identifier: "kv", + minimumQuotaMb: 256, + ports: []string{KV_PORT, KV_SSL_PORT, VIEW_PORT, VIEW_SSL_PORT}, + } + + query = service{ + identifier: "n1ql", + minimumQuotaMb: 0, + ports: []string{QUERY_PORT, QUERY_SSL_PORT}, + } + + search = service{ + identifier: "fts", + minimumQuotaMb: 256, + ports: []string{SEARCH_PORT, SEARCH_SSL_PORT}, + } + + index = service{ + identifier: "index", + minimumQuotaMb: 256, + } + + analytics = service{ + identifier: "cbas", + minimumQuotaMb: 256, + ports: []string{ANALYTICS_PORT, ANALYTICS_SSL_PORT}, + } + + eventing = service{ + identifier: "eventing", + minimumQuotaMb: 256, + ports: []string{EVENTING_PORT, EVENTING_SSL_PORT}, + } +) From 5b355b553988022782b8dd00e0d9a79dbb36b836 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Fri, 17 Feb 2023 17:39:12 +0300 Subject: [PATCH 03/40] add wait until all nodes are healthy --- modules/couchbase/couchbase.go | 61 ++++++++++++++++++++++++++++++++++ modules/couchbase/go.mod | 3 ++ modules/couchbase/go.sum | 6 ++++ 3 files changed, 70 insertions(+) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index e9f73bbe97..c9c1fb48a8 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -3,6 +3,10 @@ package couchbase import ( "context" "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + "github.com/tidwall/gjson" + "io" + "net/http" ) const ( @@ -57,6 +61,10 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e return nil, err } + if err := waitUntilAllNodesAreHealthy(ctx, container, config.enabledServices); err != nil { + return nil, err + } + return &CouchbaseContainer{Container: container}, nil } @@ -67,3 +75,56 @@ func exposePorts(req *testcontainers.ContainerRequest, enabledServices []service req.ExposedPorts = append(req.ExposedPorts, service.ports...) } } + +func waitUntilAllNodesAreHealthy(ctx context.Context, container testcontainers.Container, enabledServices []service) error { + var waitStrategy []wait.Strategy + + waitStrategy = append(waitStrategy, wait.ForHTTP("/pools/default"). + WithPort(MGMT_PORT). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }). + WithResponseMatcher(func(body io.Reader) bool { + json, err := io.ReadAll(body) + if err != nil { + return false + } + status := gjson.Get(string(json), "nodes.0.status") + if status.String() != "healthy" { + return false + } + + return true + })) + + for _, service := range enabledServices { + var strategy wait.Strategy + + switch service.identifier { + case query.identifier: + strategy = wait.ForHTTP("/admin/ping"). + WithPort(QUERY_PORT). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }) + case analytics.identifier: + strategy = wait.ForHTTP("/admin/ping"). + WithPort(ANALYTICS_PORT). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }) + case eventing.identifier: + strategy = wait.ForHTTP("/api/v1/config"). + WithPort(EVENTING_PORT). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }) + } + + if strategy != nil { + waitStrategy = append(waitStrategy, strategy) + } + } + + return wait.ForAll(waitStrategy...).WaitUntilReady(ctx, container) +} diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod index 41ece3573d..9208cb75fd 100644 --- a/modules/couchbase/go.mod +++ b/modules/couchbase/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/testcontainers/testcontainers-go v0.18.0 + github.com/tidwall/gjson v1.14.4 gotest.tools/gotestsum v1.9.0 ) @@ -36,6 +37,8 @@ require ( github.com/opencontainers/runc v1.1.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/sirupsen/logrus v1.9.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect golang.org/x/sync v0.1.0 // indirect diff --git a/modules/couchbase/go.sum b/modules/couchbase/go.sum index bf1e749f38..8d0a83ab01 100644 --- a/modules/couchbase/go.sum +++ b/modules/couchbase/go.sum @@ -144,6 +144,12 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= From 953572ff96da24881c2f65b11349cc676b197ffa Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Tue, 21 Feb 2023 15:48:38 +0300 Subject: [PATCH 04/40] add cluster initialization functions --- modules/couchbase/couchbase.go | 220 ++++++++++++++++++++++++++++++++- modules/couchbase/options.go | 10 ++ modules/couchbase/service.go | 4 + 3 files changed, 230 insertions(+), 4 deletions(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index c9c1fb48a8..edfc133d85 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -2,11 +2,17 @@ package couchbase import ( "context" + "errors" + "fmt" + "github.com/docker/go-connections/nat" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" "github.com/tidwall/gjson" "io" "net/http" + "net/url" + "strconv" + "strings" ) const ( @@ -32,15 +38,20 @@ const ( KV_SSL_PORT = "11207" ) +type clusterInit func(context.Context) error + // CouchbaseContainer represents the Couchbase container type used in the module type CouchbaseContainer struct { testcontainers.Container + config *Config } // StartContainer creates an instance of the Couchbase container type func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, error) { config := &Config{ enabledServices: []service{kv, query, search, index}, + username: "Administrator", + password: "password", } for _, opt := range opts { @@ -61,11 +72,33 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e return nil, err } - if err := waitUntilAllNodesAreHealthy(ctx, container, config.enabledServices); err != nil { + couchbaseContainer := CouchbaseContainer{container, config} + + if err = couchbaseContainer.waitUntilAllNodesAreHealthy(ctx, config.enabledServices); err != nil { return nil, err } - return &CouchbaseContainer{Container: container}, nil + clusterInitFunc := []clusterInit{ + couchbaseContainer.waitUntilNodeIsOnline, + couchbaseContainer.initializeIsEnterprise, + couchbaseContainer.renameNode, + couchbaseContainer.initializeServices, + couchbaseContainer.setMemoryQuotas, + couchbaseContainer.configureAdminUser, + couchbaseContainer.configureExternalPorts, + } + + if contains(config.enabledServices, index) { + clusterInitFunc = append(clusterInitFunc, couchbaseContainer.configureIndexer) + } + + for _, fn := range clusterInitFunc { + if err = fn(ctx); err != nil { + return nil, err + } + } + + return &couchbaseContainer, nil } func exposePorts(req *testcontainers.ContainerRequest, enabledServices []service) { @@ -76,7 +109,7 @@ func exposePorts(req *testcontainers.ContainerRequest, enabledServices []service } } -func waitUntilAllNodesAreHealthy(ctx context.Context, container testcontainers.Container, enabledServices []service) error { +func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context, enabledServices []service) error { var waitStrategy []wait.Strategy waitStrategy = append(waitStrategy, wait.ForHTTP("/pools/default"). @@ -126,5 +159,184 @@ func waitUntilAllNodesAreHealthy(ctx context.Context, container testcontainers.C } } - return wait.ForAll(waitStrategy...).WaitUntilReady(ctx, container) + return wait.ForAll(waitStrategy...).WaitUntilReady(ctx, c) +} + +func (c *CouchbaseContainer) waitUntilNodeIsOnline(ctx context.Context) error { + return wait.ForHTTP("/pools"). + WithPort(MGMT_PORT). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }). + WaitUntilReady(ctx, c) +} + +func (c *CouchbaseContainer) initializeIsEnterprise(ctx context.Context) error { + response, err := c.doHttpRequest(ctx, MGMT_PORT, "/pools", http.MethodGet, nil, false) + if err != nil { + return err + } + + c.config.isEnterprise = gjson.Get(string(response), "isEnterprise").Bool() + + if !c.config.isEnterprise { + for _, s := range c.config.enabledServices { + if s.identifier == analytics.identifier { + return errors.New("the Analytics Service is only supported with the Enterprise version") + } + if s.identifier == eventing.identifier { + return errors.New("the Eventing Service is only supported with the Enterprise version") + } + } + } + + return nil +} + +func (c *CouchbaseContainer) renameNode(ctx context.Context) error { + hostname, err := c.getInternalIPAddress(ctx) + if err != nil { + return err + } + + body := map[string]string{ + "hostname": hostname, + } + + _, err = c.doHttpRequest(ctx, MGMT_PORT, "/node/controller/rename", http.MethodPost, body, false) + + return err +} + +func (c *CouchbaseContainer) initializeServices(ctx context.Context) error { + body := map[string]string{ + "services": c.getEnabledServices(), + } + _, err := c.doHttpRequest(ctx, MGMT_PORT, "/node/controller/setupServices", http.MethodPost, body, false) + + return err +} + +func (c *CouchbaseContainer) setMemoryQuotas(ctx context.Context) error { + body := map[string]string{} + + for _, s := range c.config.enabledServices { + if !s.hasQuota() { + continue + } + + quota := strconv.Itoa(s.minimumQuotaMb) + if s.identifier == kv.identifier { + body["memoryQuota"] = quota + } else { + body[s.identifier+"MemoryQuota"] = quota + } + } + + _, err := c.doHttpRequest(ctx, MGMT_PORT, "/pools/default", http.MethodPost, body, false) + + return err +} + +func (c *CouchbaseContainer) configureAdminUser(ctx context.Context) error { + body := map[string]string{ + "username": c.config.username, + "password": c.config.password, + "port": "SAME", + } + + _, err := c.doHttpRequest(ctx, MGMT_PORT, "/settings/web", http.MethodPost, body, false) + + return err +} + +func (c *CouchbaseContainer) configureExternalPorts(ctx context.Context) error { + panic("implement it") +} + +func (c *CouchbaseContainer) configureIndexer(ctx context.Context) error { + storageMode := "forestdb" + if c.config.isEnterprise { + storageMode = "memory_optimized" + } + + body := map[string]string{ + "storageMode": storageMode, + } + + _, err := c.doHttpRequest(ctx, MGMT_PORT, "/settings/indexes", http.MethodPost, body, true) + + return err +} + +func (c *CouchbaseContainer) doHttpRequest(ctx context.Context, port, path, method string, body map[string]string, auth bool) ([]byte, error) { + form := url.Values{} + for k, v := range body { + form.Set(k, v) + } + + url, err := c.getUrl(ctx, port, path) + if err != nil { + return nil, err + } + + request, err := http.NewRequest(method, url, strings.NewReader(form.Encode())) + if err != nil { + return nil, err + } + + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + if auth { + request.SetBasicAuth(c.config.username, c.config.password) + } + + response, err := http.DefaultClient.Do(request) + if err != nil { + return nil, err + } + defer response.Body.Close() + + return io.ReadAll(response.Body) +} + +func (c *CouchbaseContainer) getUrl(ctx context.Context, port, path string) (string, error) { + host, err := c.Host(ctx) + if err != nil { + return "", err + } + + mappedPort, err := c.MappedPort(ctx, nat.Port(port)) + if err != nil { + return "", err + } + + return fmt.Sprintf("http://%s:%s%s", host, mappedPort, path), nil +} + +func (c *CouchbaseContainer) getInternalIPAddress(ctx context.Context) (string, error) { + networks, err := c.Networks(ctx) + if err != nil { + return "", err + } + + return networks[0], nil +} + +func (c *CouchbaseContainer) getEnabledServices() string { + identifiers := make([]string, len(c.config.enabledServices)) + for _, v := range c.config.enabledServices { + identifiers = append(identifiers, v.identifier) + } + + return strings.Join(identifiers, ",") +} + +func contains(services []service, service service) bool { + for _, s := range services { + if s.identifier == service.identifier { + return true + } + } + return false } diff --git a/modules/couchbase/options.go b/modules/couchbase/options.go index c609af92b4..8d8bc6b9c5 100644 --- a/modules/couchbase/options.go +++ b/modules/couchbase/options.go @@ -4,6 +4,9 @@ type Option func(*Config) type Config struct { enabledServices []service + username string + password string + isEnterprise bool } func WithEventingService() Option { @@ -17,3 +20,10 @@ func WithAnalyticsService() Option { c.enabledServices = append(c.enabledServices, analytics) } } + +func WithCredentials(username, password string) Option { + return func(c *Config) { + c.username = username + c.password = password + } +} diff --git a/modules/couchbase/service.go b/modules/couchbase/service.go index 12a761191f..e6a741d885 100644 --- a/modules/couchbase/service.go +++ b/modules/couchbase/service.go @@ -6,6 +6,10 @@ type service struct { ports []string } +func (s service) hasQuota() bool { + return s.minimumQuotaMb > 0 +} + var ( kv = service{ identifier: "kv", From a6b2493f11b131c2d634b5153720638505b465de Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Tue, 21 Feb 2023 15:59:12 +0300 Subject: [PATCH 05/40] refactor enabledServices for loop with contains method --- modules/couchbase/couchbase.go | 64 +++++++++++++++------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index edfc133d85..0c7cafe51b 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -74,7 +74,7 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e couchbaseContainer := CouchbaseContainer{container, config} - if err = couchbaseContainer.waitUntilAllNodesAreHealthy(ctx, config.enabledServices); err != nil { + if err = couchbaseContainer.waitUntilAllNodesAreHealthy(ctx); err != nil { return nil, err } @@ -109,7 +109,7 @@ func exposePorts(req *testcontainers.ContainerRequest, enabledServices []service } } -func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context, enabledServices []service) error { +func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) error { var waitStrategy []wait.Strategy waitStrategy = append(waitStrategy, wait.ForHTTP("/pools/default"). @@ -130,33 +130,29 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context, en return true })) - for _, service := range enabledServices { - var strategy wait.Strategy - - switch service.identifier { - case query.identifier: - strategy = wait.ForHTTP("/admin/ping"). - WithPort(QUERY_PORT). - WithStatusCodeMatcher(func(status int) bool { - return status == http.StatusOK - }) - case analytics.identifier: - strategy = wait.ForHTTP("/admin/ping"). - WithPort(ANALYTICS_PORT). - WithStatusCodeMatcher(func(status int) bool { - return status == http.StatusOK - }) - case eventing.identifier: - strategy = wait.ForHTTP("/api/v1/config"). - WithPort(EVENTING_PORT). - WithStatusCodeMatcher(func(status int) bool { - return status == http.StatusOK - }) - } + if contains(c.config.enabledServices, query) { + waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). + WithPort(QUERY_PORT). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }), + ) + } - if strategy != nil { - waitStrategy = append(waitStrategy, strategy) - } + if contains(c.config.enabledServices, analytics) { + waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). + WithPort(ANALYTICS_PORT). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + })) + } + + if contains(c.config.enabledServices, eventing) { + waitStrategy = append(waitStrategy, wait.ForHTTP("/api/v1/config"). + WithPort(EVENTING_PORT). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + })) } return wait.ForAll(waitStrategy...).WaitUntilReady(ctx, c) @@ -180,13 +176,11 @@ func (c *CouchbaseContainer) initializeIsEnterprise(ctx context.Context) error { c.config.isEnterprise = gjson.Get(string(response), "isEnterprise").Bool() if !c.config.isEnterprise { - for _, s := range c.config.enabledServices { - if s.identifier == analytics.identifier { - return errors.New("the Analytics Service is only supported with the Enterprise version") - } - if s.identifier == eventing.identifier { - return errors.New("the Eventing Service is only supported with the Enterprise version") - } + if contains(c.config.enabledServices, analytics) { + return errors.New("the Analytics Service is only supported with the Enterprise version") + } + if contains(c.config.enabledServices, eventing) { + return errors.New("the Eventing Service is only supported with the Enterprise version") } } From 9263849780a4e3029cca544bf4ae38fb03d203ed Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Tue, 21 Feb 2023 16:20:39 +0300 Subject: [PATCH 06/40] add configureExternalPorts --- modules/couchbase/couchbase.go | 57 +++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index 0c7cafe51b..91f2b873d5 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -245,7 +245,62 @@ func (c *CouchbaseContainer) configureAdminUser(ctx context.Context) error { } func (c *CouchbaseContainer) configureExternalPorts(ctx context.Context) error { - panic("implement it") + host, _ := c.Host(ctx) + mgmt, _ := c.MappedPort(ctx, MGMT_PORT) + mgmtSSL, _ := c.MappedPort(ctx, MGMT_SSL_PORT) + body := map[string]string{ + "hostname": host, + "mgmt": string(mgmt), + "mgmtSSL": string(mgmtSSL), + } + + if contains(c.config.enabledServices, kv) { + kv, _ := c.MappedPort(ctx, KV_PORT) + kvSSL, _ := c.MappedPort(ctx, KV_SSL_PORT) + capi, _ := c.MappedPort(ctx, VIEW_PORT) + capiSSL, _ := c.MappedPort(ctx, VIEW_SSL_PORT) + + body["kv"] = string(kv) + body["kvSSL"] = string(kvSSL) + body["capi"] = string(capi) + body["capiSSL"] = string(capiSSL) + } + + if contains(c.config.enabledServices, query) { + n1ql, _ := c.MappedPort(ctx, QUERY_PORT) + n1qlSSL, _ := c.MappedPort(ctx, KV_SSL_PORT) + + body["n1ql"] = string(n1ql) + body["n1qlSSL"] = string(n1qlSSL) + } + + if contains(c.config.enabledServices, search) { + fts, _ := c.MappedPort(ctx, SEARCH_PORT) + ftsSSL, _ := c.MappedPort(ctx, SEARCH_SSL_PORT) + + body["fts"] = string(fts) + body["ftsSSL"] = string(ftsSSL) + } + + if contains(c.config.enabledServices, analytics) { + cbas, _ := c.MappedPort(ctx, ANALYTICS_PORT) + cbasSSL, _ := c.MappedPort(ctx, ANALYTICS_SSL_PORT) + + body["cbas"] = string(cbas) + body["cbasSSL"] = string(cbasSSL) + } + + if contains(c.config.enabledServices, eventing) { + eventingAdminPort, _ := c.MappedPort(ctx, EVENTING_PORT) + eventingSSL, _ := c.MappedPort(ctx, EVENTING_SSL_PORT) + + body["eventingAdminPort"] = string(eventingAdminPort) + body["eventingSSL"] = string(eventingSSL) + } + + _, err := c.doHttpRequest(ctx, MGMT_PORT, "/node/controller/setupAlternateAddresses/external", http.MethodPut, body, true) + + return err } func (c *CouchbaseContainer) configureIndexer(ctx context.Context) error { From d5b4f1573a40f12cdf5c69786c47da32e0a48979 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Tue, 21 Feb 2023 16:22:06 +0300 Subject: [PATCH 07/40] refactor doHttpRequest to create new request with context --- modules/couchbase/couchbase.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index 91f2b873d5..6c8f0cb7ab 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -329,7 +329,7 @@ func (c *CouchbaseContainer) doHttpRequest(ctx context.Context, port, path, meth return nil, err } - request, err := http.NewRequest(method, url, strings.NewReader(form.Encode())) + request, err := http.NewRequestWithContext(ctx, method, url, strings.NewReader(form.Encode())) if err != nil { return nil, err } From 0e43367990d0241f786d219671ea49a7387ca340 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Tue, 21 Feb 2023 23:19:33 +0300 Subject: [PATCH 08/40] add create buckets --- modules/couchbase/bucket.go | 49 +++++++++++++++++++++ modules/couchbase/couchbase.go | 79 +++++++++++++++++++++++++++++++++- modules/couchbase/options.go | 7 +++ wait/http.go | 13 ++++++ 4 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 modules/couchbase/bucket.go diff --git a/modules/couchbase/bucket.go b/modules/couchbase/bucket.go new file mode 100644 index 0000000000..f25975bc22 --- /dev/null +++ b/modules/couchbase/bucket.go @@ -0,0 +1,49 @@ +package couchbase + +type bucket struct { + name string + flushEnabled bool + queryPrimaryIndex bool + quota int + numReplicas int +} + +func NewBucket(name string) *bucket { + return &bucket{ + name: name, + flushEnabled: false, + queryPrimaryIndex: true, + quota: 100, + numReplicas: 0, + } +} + +func (b *bucket) WithReplicas(numReplicas int) *bucket { + if numReplicas < 0 { + numReplicas = 0 + } else if numReplicas > 3 { + numReplicas = 3 + } + + b.numReplicas = numReplicas + return b +} + +func (b *bucket) WithFlushEnabled(flushEnabled bool) *bucket { + b.flushEnabled = flushEnabled + return b +} + +func (b *bucket) WithQuota(quota int) *bucket { + if quota < 100 { + quota = 100 + } + + b.quota = quota + return b +} + +func (b *bucket) WithPrimaryIndex(primaryIndex bool) *bucket { + b.queryPrimaryIndex = primaryIndex + return b +} diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index 6c8f0cb7ab..d65213a749 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -2,6 +2,7 @@ package couchbase import ( "context" + "encoding/json" "errors" "fmt" "github.com/docker/go-connections/nat" @@ -268,7 +269,7 @@ func (c *CouchbaseContainer) configureExternalPorts(ctx context.Context) error { if contains(c.config.enabledServices, query) { n1ql, _ := c.MappedPort(ctx, QUERY_PORT) - n1qlSSL, _ := c.MappedPort(ctx, KV_SSL_PORT) + n1qlSSL, _ := c.MappedPort(ctx, QUERY_SSL_PORT) body["n1ql"] = string(n1ql) body["n1qlSSL"] = string(n1qlSSL) @@ -318,6 +319,47 @@ func (c *CouchbaseContainer) configureIndexer(ctx context.Context) error { return err } +func (c *CouchbaseContainer) createBuckets(ctx context.Context) error { + for _, bucket := range c.config.buckets { + flushEnabled := "0" + if bucket.flushEnabled { + flushEnabled = "1" + } + body := map[string]string{ + "name": bucket.name, + "ramQuotaMB": strconv.Itoa(bucket.quota), + "flushEnabled": flushEnabled, + "replicaNumber": strconv.Itoa(bucket.numReplicas), + } + + if _, err := c.doHttpRequest(ctx, MGMT_PORT, "/pools/default/buckets", http.MethodPost, body, true); err != nil { + return err + } + + if err := wait.ForHTTP("/pools/default/b/"+bucket.name). + WithPort(MGMT_PORT). + WithBasicCredentials(c.config.username, c.config.password). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }). + WithResponseMatcher(func(body io.Reader) bool { + response, err := io.ReadAll(body) + if err != nil { + return false + } + return c.checkAllServicesEnabled(response) + }). + WaitUntilReady(ctx, c); err != nil { + return err + } + + // TODO check query service + // TODO create primary index + } + + return nil +} + func (c *CouchbaseContainer) doHttpRequest(ctx context.Context, port, path, method string, body map[string]string, auth bool) ([]byte, error) { form := url.Values{} for k, v := range body { @@ -389,3 +431,38 @@ func contains(services []service, service service) bool { } return false } + +func (c *CouchbaseContainer) checkAllServicesEnabled(rawConfig []byte) bool { + var data map[string]interface{} + if err := json.Unmarshal(rawConfig, &data); err != nil { + return false + } + + nodesExt, ok := data["nodesExt"].([]interface{}) + if !ok { + return false + } + + for _, node := range nodesExt { + services, ok := node.(map[string]interface{})["services"].(map[string]interface{}) + if !ok { + return false + } + + for _, s := range c.config.enabledServices { + found := false + for serviceName := range services { + if strings.HasPrefix(serviceName, s.identifier) { + found = true + break + } + } + + if !found { + return false + } + } + } + + return true +} diff --git a/modules/couchbase/options.go b/modules/couchbase/options.go index 8d8bc6b9c5..b1a681f9df 100644 --- a/modules/couchbase/options.go +++ b/modules/couchbase/options.go @@ -7,6 +7,7 @@ type Config struct { username string password string isEnterprise bool + buckets []bucket } func WithEventingService() Option { @@ -27,3 +28,9 @@ func WithCredentials(username, password string) Option { c.password = password } } + +func WithBucket(bucket bucket) Option { + return func(config *Config) { + config.buckets = append(config.buckets, bucket) + } +} diff --git a/wait/http.go b/wait/http.go index 67e1206b5d..a2d8efb1f8 100644 --- a/wait/http.go +++ b/wait/http.go @@ -34,6 +34,8 @@ type HTTPStrategy struct { Method string // http method Body io.Reader // http request body PollInterval time.Duration + Username string + Password string } // NewHTTPStrategy constructs a HTTP strategy waiting on port 80 and status code 200 @@ -109,6 +111,12 @@ func (ws *HTTPStrategy) WithPollInterval(pollInterval time.Duration) *HTTPStrate return ws } +func (ws *HTTPStrategy) WithBasicCredentials(username, password string) *HTTPStrategy { + ws.Username = username + ws.Password = password + return ws +} + // ForHTTP is a convenience method similar to Wait.java // https://github.com/testcontainers/testcontainers-java/blob/1d85a3834bd937f80aad3a4cec249c027f31aeb4/core/src/main/java/org/testcontainers/containers/wait/strategy/Wait.java func ForHTTP(path string) *HTTPStrategy { @@ -212,6 +220,11 @@ func (ws *HTTPStrategy) WaitUntilReady(ctx context.Context, target StrategyTarge if err != nil { return err } + + if ws.Username != "" { + req.SetBasicAuth(ws.Username, ws.Password) + } + resp, err := client.Do(req) if err != nil { continue From c8b37142b9c5ddc34a2a7c7ba708facb3e0b0acf Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Wed, 22 Feb 2023 23:11:31 +0300 Subject: [PATCH 09/40] complete create bucket flow --- modules/couchbase/couchbase.go | 151 +++++++++++++++++++++++++++------ 1 file changed, 123 insertions(+), 28 deletions(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index d65213a749..66bf39c924 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/cenkalti/backoff/v4" "github.com/docker/go-connections/nat" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" @@ -99,6 +100,11 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e } } + err = couchbaseContainer.createBuckets(ctx) + if err != nil { + return nil, err + } + return &couchbaseContainer, nil } @@ -119,11 +125,11 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) er return status == http.StatusOK }). WithResponseMatcher(func(body io.Reader) bool { - json, err := io.ReadAll(body) + response, err := io.ReadAll(body) if err != nil { return false } - status := gjson.Get(string(json), "nodes.0.status") + status := gjson.Get(string(response), "nodes.0.status") if status.String() != "healthy" { return false } @@ -321,43 +327,132 @@ func (c *CouchbaseContainer) configureIndexer(ctx context.Context) error { func (c *CouchbaseContainer) createBuckets(ctx context.Context) error { for _, bucket := range c.config.buckets { - flushEnabled := "0" - if bucket.flushEnabled { - flushEnabled = "1" + err := c.createBucket(ctx, bucket) + if err != nil { + return err } - body := map[string]string{ - "name": bucket.name, - "ramQuotaMB": strconv.Itoa(bucket.quota), - "flushEnabled": flushEnabled, - "replicaNumber": strconv.Itoa(bucket.numReplicas), + + err = c.waitForAllServicesEnabled(ctx, bucket) + if err != nil { + return err + } + if contains(c.config.enabledServices, query) { + err = c.isQueryKeyspacePresent(ctx, bucket) + if err != nil { + return err + } } - if _, err := c.doHttpRequest(ctx, MGMT_PORT, "/pools/default/buckets", http.MethodPost, body, true); err != nil { + if bucket.queryPrimaryIndex { + if !contains(c.config.enabledServices, query) { + return fmt.Errorf("primary index creation for bucket %s ignored, since QUERY service is not present", bucket.name) + } + + err = c.createPrimaryIndex(ctx, bucket) + if err != nil { + return err + } + + err = c.isPrimaryIndexOnline(ctx, bucket, err) + if err != nil { + return err + } + + } + } + + return nil +} + +func (c *CouchbaseContainer) isPrimaryIndexOnline(ctx context.Context, bucket bucket, err error) error { + body := map[string]string{ + "statement": "SELECT count(*) > 0 AS online FROM system:indexes where keyspace_id = \"" + + bucket.name + + "\" and is_primary = true and state = \"online\"", + } + + err = backoff.Retry(func() error { + response, err := c.doHttpRequest(ctx, QUERY_PORT, "/query/service", http.MethodPost, body, true) + if err != nil { return err } - if err := wait.ForHTTP("/pools/default/b/"+bucket.name). - WithPort(MGMT_PORT). - WithBasicCredentials(c.config.username, c.config.password). - WithStatusCodeMatcher(func(status int) bool { - return status == http.StatusOK - }). - WithResponseMatcher(func(body io.Reader) bool { - response, err := io.ReadAll(body) - if err != nil { - return false - } - return c.checkAllServicesEnabled(response) - }). - WaitUntilReady(ctx, c); err != nil { + online := gjson.Get(string(response), "results.0.online").Bool() + if !online { + return errors.New("primary index state is not online") + } + + return nil + }, backoff.WithContext(backoff.NewExponentialBackOff(), ctx)) + + return err +} + +func (c *CouchbaseContainer) createPrimaryIndex(ctx context.Context, bucket bucket) error { + body := map[string]string{ + "statement": "CREATE PRIMARY INDEX on `" + bucket.name + "`", + } + + _, err := c.doHttpRequest(ctx, QUERY_PORT, "/query/service", http.MethodPost, body, true) + + return err +} + +func (c *CouchbaseContainer) isQueryKeyspacePresent(ctx context.Context, bucket bucket) error { + body := map[string]string{ + "statement": "SELECT COUNT(*) > 0 as present FROM system:keyspaces WHERE name = \"" + bucket.name + "\"", + } + + err := backoff.Retry(func() error { + response, err := c.doHttpRequest(ctx, QUERY_PORT, "/query/service", http.MethodPost, body, true) + if err != nil { return err } + present := gjson.Get(string(response), "results.0.present").Bool() + if !present { + return errors.New("query namespace is not present") + } - // TODO check query service - // TODO create primary index + return nil + }, backoff.WithContext(backoff.NewExponentialBackOff(), ctx)) + + return err +} + +func (c *CouchbaseContainer) waitForAllServicesEnabled(ctx context.Context, bucket bucket) error { + err := wait.ForHTTP("/pools/default/b/"+bucket.name). + WithPort(MGMT_PORT). + WithBasicCredentials(c.config.username, c.config.password). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }). + WithResponseMatcher(func(body io.Reader) bool { + response, err := io.ReadAll(body) + if err != nil { + return false + } + return c.checkAllServicesEnabled(response) + }). + WaitUntilReady(ctx, c) + + return err +} + +func (c *CouchbaseContainer) createBucket(ctx context.Context, bucket bucket) error { + flushEnabled := "0" + if bucket.flushEnabled { + flushEnabled = "1" + } + body := map[string]string{ + "name": bucket.name, + "ramQuotaMB": strconv.Itoa(bucket.quota), + "flushEnabled": flushEnabled, + "replicaNumber": strconv.Itoa(bucket.numReplicas), } - return nil + _, err := c.doHttpRequest(ctx, MGMT_PORT, "/pools/default/buckets", http.MethodPost, body, true) + + return err } func (c *CouchbaseContainer) doHttpRequest(ctx context.Context, port, path, method string, body map[string]string, auth bool) ([]byte, error) { From b78012c78d03127dc10cbdb296b8452758014f20 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Wed, 22 Feb 2023 23:18:22 +0300 Subject: [PATCH 10/40] add docker image name to config --- modules/couchbase/couchbase.go | 3 ++- modules/couchbase/options.go | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index 66bf39c924..553ee0736c 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -54,6 +54,7 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e enabledServices: []service{kv, query, search, index}, username: "Administrator", password: "password", + imageName: "couchbase:6.5.1", } for _, opt := range opts { @@ -61,7 +62,7 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e } req := testcontainers.ContainerRequest{ - Image: "couchbase:6.5.1", + Image: config.imageName, } exposePorts(&req, config.enabledServices) diff --git a/modules/couchbase/options.go b/modules/couchbase/options.go index b1a681f9df..074bf1e88b 100644 --- a/modules/couchbase/options.go +++ b/modules/couchbase/options.go @@ -8,6 +8,7 @@ type Config struct { password string isEnterprise bool buckets []bucket + imageName string } func WithEventingService() Option { @@ -30,7 +31,13 @@ func WithCredentials(username, password string) Option { } func WithBucket(bucket bucket) Option { - return func(config *Config) { - config.buckets = append(config.buckets, bucket) + return func(c *Config) { + c.buckets = append(c.buckets, bucket) + } +} + +func WithImageName(imageName string) Option { + return func(c *Config) { + c.imageName = imageName } } From becc912ed5679ff31d19398d5ffc50d99f0fc090 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Sat, 25 Feb 2023 00:50:18 +0300 Subject: [PATCH 11/40] fix port suffix, mapped port, enabled services and refactor checkAllServicesEnabled with gjson --- modules/couchbase/couchbase.go | 55 +++++++++++++++++----------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index 553ee0736c..c937b3b62b 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -2,7 +2,6 @@ package couchbase import ( "context" - "encoding/json" "errors" "fmt" "github.com/cenkalti/backoff/v4" @@ -62,11 +61,10 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e } req := testcontainers.ContainerRequest{ - Image: config.imageName, + Image: config.imageName, + ExposedPorts: exposePorts(config.enabledServices), } - exposePorts(&req, config.enabledServices) - container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: req, Started: true, @@ -77,10 +75,6 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e couchbaseContainer := CouchbaseContainer{container, config} - if err = couchbaseContainer.waitUntilAllNodesAreHealthy(ctx); err != nil { - return nil, err - } - clusterInitFunc := []clusterInit{ couchbaseContainer.waitUntilNodeIsOnline, couchbaseContainer.initializeIsEnterprise, @@ -95,6 +89,8 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e clusterInitFunc = append(clusterInitFunc, couchbaseContainer.configureIndexer) } + clusterInitFunc = append(clusterInitFunc, couchbaseContainer.waitUntilAllNodesAreHealthy) + for _, fn := range clusterInitFunc { if err = fn(ctx); err != nil { return nil, err @@ -109,12 +105,16 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e return &couchbaseContainer, nil } -func exposePorts(req *testcontainers.ContainerRequest, enabledServices []service) { - req.ExposedPorts = append(req.ExposedPorts, MGMT_PORT, MGMT_SSL_PORT) +func exposePorts(enabledServices []service) []string { + exposedPorts := []string{MGMT_PORT + "/tcp", MGMT_SSL_PORT + "/tcp"} for _, service := range enabledServices { - req.ExposedPorts = append(req.ExposedPorts, service.ports...) + for _, port := range service.ports { + exposedPorts = append(exposedPorts, port+"/tcp") + } } + + return exposedPorts } func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) error { @@ -122,6 +122,7 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) er waitStrategy = append(waitStrategy, wait.ForHTTP("/pools/default"). WithPort(MGMT_PORT). + WithBasicCredentials(c.config.username, c.config.password). WithStatusCodeMatcher(func(status int) bool { return status == http.StatusOK }). @@ -141,6 +142,7 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) er if contains(c.config.enabledServices, query) { waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). WithPort(QUERY_PORT). + WithBasicCredentials(c.config.username, c.config.password). WithStatusCodeMatcher(func(status int) bool { return status == http.StatusOK }), @@ -150,6 +152,7 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) er if contains(c.config.enabledServices, analytics) { waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). WithPort(ANALYTICS_PORT). + WithBasicCredentials(c.config.username, c.config.password). WithStatusCodeMatcher(func(status int) bool { return status == http.StatusOK })) @@ -158,6 +161,7 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) er if contains(c.config.enabledServices, eventing) { waitStrategy = append(waitStrategy, wait.ForHTTP("/api/v1/config"). WithPort(EVENTING_PORT). + WithBasicCredentials(c.config.username, c.config.password). WithStatusCodeMatcher(func(status int) bool { return status == http.StatusOK })) @@ -337,6 +341,7 @@ func (c *CouchbaseContainer) createBuckets(ctx context.Context) error { if err != nil { return err } + if contains(c.config.enabledServices, query) { err = c.isQueryKeyspacePresent(ctx, bucket) if err != nil { @@ -498,22 +503,22 @@ func (c *CouchbaseContainer) getUrl(ctx context.Context, port, path string) (str return "", err } - return fmt.Sprintf("http://%s:%s%s", host, mappedPort, path), nil + return fmt.Sprintf("http://%s:%d%s", host, mappedPort.Int(), path), nil } func (c *CouchbaseContainer) getInternalIPAddress(ctx context.Context) (string, error) { - networks, err := c.Networks(ctx) + networks, err := c.ContainerIP(ctx) if err != nil { return "", err } - return networks[0], nil + return networks, nil } func (c *CouchbaseContainer) getEnabledServices() string { identifiers := make([]string, len(c.config.enabledServices)) - for _, v := range c.config.enabledServices { - identifiers = append(identifiers, v.identifier) + for i, v := range c.config.enabledServices { + identifiers[i] = v.identifier } return strings.Join(identifiers, ",") @@ -529,28 +534,22 @@ func contains(services []service, service service) bool { } func (c *CouchbaseContainer) checkAllServicesEnabled(rawConfig []byte) bool { - var data map[string]interface{} - if err := json.Unmarshal(rawConfig, &data); err != nil { - return false - } - - nodesExt, ok := data["nodesExt"].([]interface{}) - if !ok { + nodeExt := gjson.Get(string(rawConfig), "nodesExt") + if !nodeExt.Exists() { return false } - for _, node := range nodesExt { - services, ok := node.(map[string]interface{})["services"].(map[string]interface{}) - if !ok { + for _, node := range nodeExt.Array() { + services := node.Map()["services"] + if !services.Exists() { return false } for _, s := range c.config.enabledServices { found := false - for serviceName := range services { + for serviceName := range services.Map() { if strings.HasPrefix(serviceName, s.identifier) { found = true - break } } From ca302554bbf641fdbbf06f0a635af5944f7ddd9d Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Sat, 25 Feb 2023 00:56:40 +0300 Subject: [PATCH 12/40] add initCluster method --- modules/couchbase/couchbase.go | 181 +++++++++++++++++---------------- 1 file changed, 94 insertions(+), 87 deletions(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index c937b3b62b..cdcf46daba 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -75,99 +75,41 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e couchbaseContainer := CouchbaseContainer{container, config} - clusterInitFunc := []clusterInit{ - couchbaseContainer.waitUntilNodeIsOnline, - couchbaseContainer.initializeIsEnterprise, - couchbaseContainer.renameNode, - couchbaseContainer.initializeServices, - couchbaseContainer.setMemoryQuotas, - couchbaseContainer.configureAdminUser, - couchbaseContainer.configureExternalPorts, - } - - if contains(config.enabledServices, index) { - clusterInitFunc = append(clusterInitFunc, couchbaseContainer.configureIndexer) - } - - clusterInitFunc = append(clusterInitFunc, couchbaseContainer.waitUntilAllNodesAreHealthy) - - for _, fn := range clusterInitFunc { - if err = fn(ctx); err != nil { - return nil, err - } + if err = couchbaseContainer.initCluster(ctx); err != nil { + return nil, err } - err = couchbaseContainer.createBuckets(ctx) - if err != nil { + if err = couchbaseContainer.createBuckets(ctx); err != nil { return nil, err } return &couchbaseContainer, nil } -func exposePorts(enabledServices []service) []string { - exposedPorts := []string{MGMT_PORT + "/tcp", MGMT_SSL_PORT + "/tcp"} - - for _, service := range enabledServices { - for _, port := range service.ports { - exposedPorts = append(exposedPorts, port+"/tcp") - } +func (c *CouchbaseContainer) initCluster(ctx context.Context) error { + clusterInitFunc := []clusterInit{ + c.waitUntilNodeIsOnline, + c.initializeIsEnterprise, + c.renameNode, + c.initializeServices, + c.setMemoryQuotas, + c.configureAdminUser, + c.configureExternalPorts, } - return exposedPorts -} - -func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) error { - var waitStrategy []wait.Strategy - - waitStrategy = append(waitStrategy, wait.ForHTTP("/pools/default"). - WithPort(MGMT_PORT). - WithBasicCredentials(c.config.username, c.config.password). - WithStatusCodeMatcher(func(status int) bool { - return status == http.StatusOK - }). - WithResponseMatcher(func(body io.Reader) bool { - response, err := io.ReadAll(body) - if err != nil { - return false - } - status := gjson.Get(string(response), "nodes.0.status") - if status.String() != "healthy" { - return false - } - - return true - })) - - if contains(c.config.enabledServices, query) { - waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). - WithPort(QUERY_PORT). - WithBasicCredentials(c.config.username, c.config.password). - WithStatusCodeMatcher(func(status int) bool { - return status == http.StatusOK - }), - ) + if contains(c.config.enabledServices, index) { + clusterInitFunc = append(clusterInitFunc, c.configureIndexer) } - if contains(c.config.enabledServices, analytics) { - waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). - WithPort(ANALYTICS_PORT). - WithBasicCredentials(c.config.username, c.config.password). - WithStatusCodeMatcher(func(status int) bool { - return status == http.StatusOK - })) - } + clusterInitFunc = append(clusterInitFunc, c.waitUntilAllNodesAreHealthy) - if contains(c.config.enabledServices, eventing) { - waitStrategy = append(waitStrategy, wait.ForHTTP("/api/v1/config"). - WithPort(EVENTING_PORT). - WithBasicCredentials(c.config.username, c.config.password). - WithStatusCodeMatcher(func(status int) bool { - return status == http.StatusOK - })) + for _, fn := range clusterInitFunc { + if err := fn(ctx); err != nil { + return err + } } - return wait.ForAll(waitStrategy...).WaitUntilReady(ctx, c) + return nil } func (c *CouchbaseContainer) waitUntilNodeIsOnline(ctx context.Context) error { @@ -330,6 +272,59 @@ func (c *CouchbaseContainer) configureIndexer(ctx context.Context) error { return err } +func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) error { + var waitStrategy []wait.Strategy + + waitStrategy = append(waitStrategy, wait.ForHTTP("/pools/default"). + WithPort(MGMT_PORT). + WithBasicCredentials(c.config.username, c.config.password). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }). + WithResponseMatcher(func(body io.Reader) bool { + response, err := io.ReadAll(body) + if err != nil { + return false + } + status := gjson.Get(string(response), "nodes.0.status") + if status.String() != "healthy" { + return false + } + + return true + })) + + if contains(c.config.enabledServices, query) { + waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). + WithPort(QUERY_PORT). + WithBasicCredentials(c.config.username, c.config.password). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + }), + ) + } + + if contains(c.config.enabledServices, analytics) { + waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). + WithPort(ANALYTICS_PORT). + WithBasicCredentials(c.config.username, c.config.password). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + })) + } + + if contains(c.config.enabledServices, eventing) { + waitStrategy = append(waitStrategy, wait.ForHTTP("/api/v1/config"). + WithPort(EVENTING_PORT). + WithBasicCredentials(c.config.username, c.config.password). + WithStatusCodeMatcher(func(status int) bool { + return status == http.StatusOK + })) + } + + return wait.ForAll(waitStrategy...).WaitUntilReady(ctx, c) +} + func (c *CouchbaseContainer) createBuckets(ctx context.Context) error { for _, bucket := range c.config.buckets { err := c.createBucket(ctx, bucket) @@ -524,15 +519,6 @@ func (c *CouchbaseContainer) getEnabledServices() string { return strings.Join(identifiers, ",") } -func contains(services []service, service service) bool { - for _, s := range services { - if s.identifier == service.identifier { - return true - } - } - return false -} - func (c *CouchbaseContainer) checkAllServicesEnabled(rawConfig []byte) bool { nodeExt := gjson.Get(string(rawConfig), "nodesExt") if !nodeExt.Exists() { @@ -561,3 +547,24 @@ func (c *CouchbaseContainer) checkAllServicesEnabled(rawConfig []byte) bool { return true } + +func exposePorts(enabledServices []service) []string { + exposedPorts := []string{MGMT_PORT + "/tcp", MGMT_SSL_PORT + "/tcp"} + + for _, service := range enabledServices { + for _, port := range service.ports { + exposedPorts = append(exposedPorts, port+"/tcp") + } + } + + return exposedPorts +} + +func contains(services []service, service service) bool { + for _, s := range services { + if s.identifier == service.identifier { + return true + } + } + return false +} From 8744d2e5f8e02ca66b799579981777f47467e68c Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Sat, 25 Feb 2023 01:08:13 +0300 Subject: [PATCH 13/40] refactor bucket definition --- modules/couchbase/bucket.go | 12 ++++++------ modules/couchbase/couchbase.go | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/couchbase/bucket.go b/modules/couchbase/bucket.go index f25975bc22..cfef779d8c 100644 --- a/modules/couchbase/bucket.go +++ b/modules/couchbase/bucket.go @@ -8,8 +8,8 @@ type bucket struct { numReplicas int } -func NewBucket(name string) *bucket { - return &bucket{ +func NewBucket(name string) bucket { + return bucket{ name: name, flushEnabled: false, queryPrimaryIndex: true, @@ -18,7 +18,7 @@ func NewBucket(name string) *bucket { } } -func (b *bucket) WithReplicas(numReplicas int) *bucket { +func (b bucket) WithReplicas(numReplicas int) bucket { if numReplicas < 0 { numReplicas = 0 } else if numReplicas > 3 { @@ -29,12 +29,12 @@ func (b *bucket) WithReplicas(numReplicas int) *bucket { return b } -func (b *bucket) WithFlushEnabled(flushEnabled bool) *bucket { +func (b bucket) WithFlushEnabled(flushEnabled bool) bucket { b.flushEnabled = flushEnabled return b } -func (b *bucket) WithQuota(quota int) *bucket { +func (b bucket) WithQuota(quota int) bucket { if quota < 100 { quota = 100 } @@ -43,7 +43,7 @@ func (b *bucket) WithQuota(quota int) *bucket { return b } -func (b *bucket) WithPrimaryIndex(primaryIndex bool) *bucket { +func (b bucket) WithPrimaryIndex(primaryIndex bool) bucket { b.queryPrimaryIndex = primaryIndex return b } diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index cdcf46daba..ddb4ecaaf1 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -354,7 +354,7 @@ func (c *CouchbaseContainer) createBuckets(ctx context.Context) error { return err } - err = c.isPrimaryIndexOnline(ctx, bucket, err) + err = c.isPrimaryIndexOnline(ctx, bucket) if err != nil { return err } @@ -365,14 +365,14 @@ func (c *CouchbaseContainer) createBuckets(ctx context.Context) error { return nil } -func (c *CouchbaseContainer) isPrimaryIndexOnline(ctx context.Context, bucket bucket, err error) error { +func (c *CouchbaseContainer) isPrimaryIndexOnline(ctx context.Context, bucket bucket) error { body := map[string]string{ "statement": "SELECT count(*) > 0 AS online FROM system:indexes where keyspace_id = \"" + bucket.name + "\" and is_primary = true and state = \"online\"", } - err = backoff.Retry(func() error { + err := backoff.Retry(func() error { response, err := c.doHttpRequest(ctx, QUERY_PORT, "/query/service", http.MethodPost, body, true) if err != nil { return err From ea85e5238fcdc21d8d01fab4d9ef6910191eb5d0 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Sat, 25 Feb 2023 01:08:42 +0300 Subject: [PATCH 14/40] update module name --- modules/couchbase/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod index 9208cb75fd..802a72a716 100644 --- a/modules/couchbase/go.mod +++ b/modules/couchbase/go.mod @@ -1,4 +1,4 @@ -module github.com/testcontainers/testcontainers-go/examples/couchbase +module github.com/testcontainers/testcontainers-go/modules/couchbase go 1.18 From c1d09144fe4cec912cee8aa27aeec7cae265dc9e Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Sat, 25 Feb 2023 22:53:50 +0300 Subject: [PATCH 15/40] add ConnectionString, Username, Password for test case and fix configure external port --- modules/couchbase/couchbase.go | 50 ++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index ddb4ecaaf1..a1fdc01790 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -86,6 +86,28 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e return &couchbaseContainer, nil } +func (c *CouchbaseContainer) ConnectionString(ctx context.Context) (string, error) { + host, err := c.Host(ctx) + if err != nil { + return "", err + } + + port, err := c.MappedPort(ctx, KV_PORT) + if err != nil { + return "", err + } + + return fmt.Sprintf("couchbase://%s:%d", host, port.Int()), nil +} + +func (c *CouchbaseContainer) Username() string { + return c.config.username +} + +func (c *CouchbaseContainer) Password() string { + return c.config.password +} + func (c *CouchbaseContainer) initCluster(ctx context.Context) error { clusterInitFunc := []clusterInit{ c.waitUntilNodeIsOnline, @@ -204,8 +226,8 @@ func (c *CouchbaseContainer) configureExternalPorts(ctx context.Context) error { mgmtSSL, _ := c.MappedPort(ctx, MGMT_SSL_PORT) body := map[string]string{ "hostname": host, - "mgmt": string(mgmt), - "mgmtSSL": string(mgmtSSL), + "mgmt": mgmt.Port(), + "mgmtSSL": mgmtSSL.Port(), } if contains(c.config.enabledServices, kv) { @@ -214,42 +236,42 @@ func (c *CouchbaseContainer) configureExternalPorts(ctx context.Context) error { capi, _ := c.MappedPort(ctx, VIEW_PORT) capiSSL, _ := c.MappedPort(ctx, VIEW_SSL_PORT) - body["kv"] = string(kv) - body["kvSSL"] = string(kvSSL) - body["capi"] = string(capi) - body["capiSSL"] = string(capiSSL) + body["kv"] = kv.Port() + body["kvSSL"] = kvSSL.Port() + body["capi"] = capi.Port() + body["capiSSL"] = capiSSL.Port() } if contains(c.config.enabledServices, query) { n1ql, _ := c.MappedPort(ctx, QUERY_PORT) n1qlSSL, _ := c.MappedPort(ctx, QUERY_SSL_PORT) - body["n1ql"] = string(n1ql) - body["n1qlSSL"] = string(n1qlSSL) + body["n1ql"] = n1ql.Port() + body["n1qlSSL"] = n1qlSSL.Port() } if contains(c.config.enabledServices, search) { fts, _ := c.MappedPort(ctx, SEARCH_PORT) ftsSSL, _ := c.MappedPort(ctx, SEARCH_SSL_PORT) - body["fts"] = string(fts) - body["ftsSSL"] = string(ftsSSL) + body["fts"] = fts.Port() + body["ftsSSL"] = ftsSSL.Port() } if contains(c.config.enabledServices, analytics) { cbas, _ := c.MappedPort(ctx, ANALYTICS_PORT) cbasSSL, _ := c.MappedPort(ctx, ANALYTICS_SSL_PORT) - body["cbas"] = string(cbas) - body["cbasSSL"] = string(cbasSSL) + body["cbas"] = cbas.Port() + body["cbasSSL"] = cbasSSL.Port() } if contains(c.config.enabledServices, eventing) { eventingAdminPort, _ := c.MappedPort(ctx, EVENTING_PORT) eventingSSL, _ := c.MappedPort(ctx, EVENTING_SSL_PORT) - body["eventingAdminPort"] = string(eventingAdminPort) - body["eventingSSL"] = string(eventingSSL) + body["eventingAdminPort"] = eventingAdminPort.Port() + body["eventingSSL"] = eventingSSL.Port() } _, err := c.doHttpRequest(ctx, MGMT_PORT, "/node/controller/setupAlternateAddresses/external", http.MethodPut, body, true) From 4badc7b8de890e100fa37157eaeb2d332d2af9e0 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Sat, 25 Feb 2023 23:17:44 +0300 Subject: [PATCH 16/40] add test --- modules/couchbase/couchbase_test.go | 49 +++++++++++++++++++++++++++-- modules/couchbase/go.mod | 6 ++-- modules/couchbase/go.sum | 15 +++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/modules/couchbase/couchbase_test.go b/modules/couchbase/couchbase_test.go index 9951bb801e..6e39034d0b 100644 --- a/modules/couchbase/couchbase_test.go +++ b/modules/couchbase/couchbase_test.go @@ -2,13 +2,16 @@ package couchbase import ( "context" + "github.com/couchbase/gocb/v2" "testing" + "time" ) func TestCouchbase(t *testing.T) { ctx := context.Background() - container, err := StartContainer(ctx) + bucketName := "testBucket" + container, err := StartContainer(ctx, WithImageName("couchbase:7.1.3"), WithBucket(NewBucket(bucketName))) if err != nil { t.Fatal(err) } @@ -20,5 +23,47 @@ func TestCouchbase(t *testing.T) { } }) - // perform assertions + cluster, err := connectCluster(ctx, container) + if err != nil { + t.Fatalf("could not connect couchbase: %s", err) + } + + bucket := cluster.Bucket(bucketName) + + err = bucket.WaitUntilReady(5*time.Second, nil) + if err != nil { + t.Fatalf("could not connect bucket: %s", err) + } + + key := "foo" + data := map[string]string{"key": "value"} + collection := bucket.DefaultCollection() + + _, err = collection.Upsert(key, data, nil) + if err != nil { + t.Fatalf("could not upsert data: %s", err) + } + + result, err := collection.Get(key, nil) + if err != nil { + t.Fatalf("could not get data: %s", err) + } + + var resultData map[string]string + err = result.Content(&resultData) + if resultData["key"] != "value" { + t.Errorf("Expected value to be [%s], got %s", "value", resultData["key"]) + } +} + +func connectCluster(ctx context.Context, container *CouchbaseContainer) (*gocb.Cluster, error) { + connectionString, err := container.ConnectionString(ctx) + if err != nil { + return nil, err + } + + return gocb.Connect(connectionString, gocb.ClusterOptions{ + Username: container.Username(), + Password: container.Password(), + }) } diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod index 802a72a716..36497f9cfe 100644 --- a/modules/couchbase/go.mod +++ b/modules/couchbase/go.mod @@ -3,6 +3,8 @@ module github.com/testcontainers/testcontainers-go/modules/couchbase go 1.18 require ( + github.com/cenkalti/backoff/v4 v4.2.0 + github.com/couchbase/gocb/v2 v2.6.1 github.com/testcontainers/testcontainers-go v0.18.0 github.com/tidwall/gjson v1.14.4 gotest.tools/gotestsum v1.9.0 @@ -11,17 +13,17 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/containerd/containerd v1.6.17 // indirect + github.com/couchbase/gocbcore/v10 v10.2.1 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/docker v23.0.0+incompatible // indirect - github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect github.com/klauspost/compress v1.15.9 // indirect diff --git a/modules/couchbase/go.sum b/modules/couchbase/go.sum index 8d0a83ab01..b66dc76977 100644 --- a/modules/couchbase/go.sum +++ b/modules/couchbase/go.sum @@ -25,6 +25,12 @@ github.com/containerd/containerd v1.6.17 h1:XDnJIeJW0cLf6v7/+N+6L9kGrChHeXekZp2V github.com/containerd/containerd v1.6.17/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/couchbase/gocb/v2 v2.6.1 h1:2/ACkqvy/PPp9hd/B9f8N4sUGVauqFOuVWoOgpdYA7U= +github.com/couchbase/gocb/v2 v2.6.1/go.mod h1:qFMQJUna2RQaGyYS87J0jxOBhprhfLCUz64apvI9FPc= +github.com/couchbase/gocbcore/v10 v10.2.1 h1:C5zXZUWdKrE2hncDBdDLRoKXNaVc7BYrn6JOgNZAODA= +github.com/couchbase/gocbcore/v10 v10.2.1/go.mod h1:Y3S2HKwqDDcsOXdsB5YRtd2wn5ADnOQwT7G00vVylh4= +github.com/couchbaselabs/gocaves/client v0.0.0-20221010100422-25779db8de05 h1:A3GRyDjp5MhqHxrGB0Hl95cCuA70Ovquy26kAJAAeZ0= +github.com/couchbaselabs/gocaves/client v0.0.0-20221010100422-25779db8de05/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= @@ -74,6 +80,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -139,10 +147,16 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -287,6 +301,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/gotestsum v1.9.0 h1:Jbo/0k/sIOXIJu51IZxEAt27n77xspFEfL6SqKUR72A= gotest.tools/gotestsum v1.9.0/go.mod h1:6JHCiN6TEjA7Kaz23q1bH0e2Dc3YJjDUZ0DmctFZf+w= gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= From 04443f12c7712b5eb78d99c74a9355463a86df44 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Sat, 25 Feb 2023 23:33:50 +0300 Subject: [PATCH 17/40] goimports and go mod tidy --- modules/couchbase/couchbase.go | 11 ++++++----- modules/couchbase/couchbase_test.go | 3 ++- modules/couchbase/go.mod | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index a1fdc01790..43b287782e 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -4,16 +4,17 @@ import ( "context" "errors" "fmt" - "github.com/cenkalti/backoff/v4" - "github.com/docker/go-connections/nat" - "github.com/testcontainers/testcontainers-go" - "github.com/testcontainers/testcontainers-go/wait" - "github.com/tidwall/gjson" "io" "net/http" "net/url" "strconv" "strings" + + "github.com/cenkalti/backoff/v4" + "github.com/docker/go-connections/nat" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + "github.com/tidwall/gjson" ) const ( diff --git a/modules/couchbase/couchbase_test.go b/modules/couchbase/couchbase_test.go index 6e39034d0b..d820cf4207 100644 --- a/modules/couchbase/couchbase_test.go +++ b/modules/couchbase/couchbase_test.go @@ -2,9 +2,10 @@ package couchbase import ( "context" - "github.com/couchbase/gocb/v2" "testing" "time" + + "github.com/couchbase/gocb/v2" ) func TestCouchbase(t *testing.T) { diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod index 36497f9cfe..66a8840c6f 100644 --- a/modules/couchbase/go.mod +++ b/modules/couchbase/go.mod @@ -5,6 +5,7 @@ go 1.18 require ( github.com/cenkalti/backoff/v4 v4.2.0 github.com/couchbase/gocb/v2 v2.6.1 + github.com/docker/go-connections v0.4.0 github.com/testcontainers/testcontainers-go v0.18.0 github.com/tidwall/gjson v1.14.4 gotest.tools/gotestsum v1.9.0 From 88e68115fd0926f9439055e38ca6f89369c99f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 27 Feb 2023 19:07:10 +0100 Subject: [PATCH 18/40] fix: use modules instead of example --- .github/workflows/module-couchbase.yml | 6 +++--- docs/modules/couchbase.md | 4 ++-- modules/couchbase/tools/tools.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/module-couchbase.yml b/.github/workflows/module-couchbase.yml index 3d85462e04..e1f66d6b36 100644 --- a/.github/workflows/module-couchbase.yml +++ b/.github/workflows/module-couchbase.yml @@ -24,15 +24,15 @@ jobs: uses: actions/checkout@v3 - name: modVerify - working-directory: ./examples/couchbase + working-directory: ./modules/couchbase run: go mod verify - name: modTidy - working-directory: ./examples/couchbase + working-directory: ./modules/couchbase run: make tools-tidy - name: gotestsum - working-directory: ./examples/couchbase + working-directory: ./modules/couchbase run: make test-unit - name: Run checker diff --git a/docs/modules/couchbase.md b/docs/modules/couchbase.md index 61513356f8..bf3492c926 100644 --- a/docs/modules/couchbase.md +++ b/docs/modules/couchbase.md @@ -1,9 +1,9 @@ # Couchbase -[Creating a Couchbase container](../../examples/couchbase/couchbase.go) +[Creating a Couchbase container](../../modules/couchbase/couchbase.go) -[Test for a Couchbase container](../../examples/couchbase/couchbase_test.go) +[Test for a Couchbase container](../../modules/couchbase/couchbase_test.go) diff --git a/modules/couchbase/tools/tools.go b/modules/couchbase/tools/tools.go index ea5b168ede..597366dbff 100644 --- a/modules/couchbase/tools/tools.go +++ b/modules/couchbase/tools/tools.go @@ -1,7 +1,7 @@ //go:build tools // +build tools -// This package contains the tool dependencies of the Couchbase example. +// This package contains the tool dependencies of the Couchbase module. package tools From d42ed480983cd16c1bb2352babb4ff8ce2f90fd7 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Tue, 28 Feb 2023 21:57:40 +0300 Subject: [PATCH 19/40] change WithBasicCredentials with WithBasicAuth --- modules/couchbase/couchbase.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index 43b287782e..bff545ebd8 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -300,7 +300,7 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) er waitStrategy = append(waitStrategy, wait.ForHTTP("/pools/default"). WithPort(MGMT_PORT). - WithBasicCredentials(c.config.username, c.config.password). + WithBasicAuth(c.config.username, c.config.password). WithStatusCodeMatcher(func(status int) bool { return status == http.StatusOK }). @@ -320,7 +320,7 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) er if contains(c.config.enabledServices, query) { waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). WithPort(QUERY_PORT). - WithBasicCredentials(c.config.username, c.config.password). + WithBasicAuth(c.config.username, c.config.password). WithStatusCodeMatcher(func(status int) bool { return status == http.StatusOK }), @@ -330,7 +330,7 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) er if contains(c.config.enabledServices, analytics) { waitStrategy = append(waitStrategy, wait.ForHTTP("/admin/ping"). WithPort(ANALYTICS_PORT). - WithBasicCredentials(c.config.username, c.config.password). + WithBasicAuth(c.config.username, c.config.password). WithStatusCodeMatcher(func(status int) bool { return status == http.StatusOK })) @@ -339,7 +339,7 @@ func (c *CouchbaseContainer) waitUntilAllNodesAreHealthy(ctx context.Context) er if contains(c.config.enabledServices, eventing) { waitStrategy = append(waitStrategy, wait.ForHTTP("/api/v1/config"). WithPort(EVENTING_PORT). - WithBasicCredentials(c.config.username, c.config.password). + WithBasicAuth(c.config.username, c.config.password). WithStatusCodeMatcher(func(status int) bool { return status == http.StatusOK })) @@ -446,7 +446,7 @@ func (c *CouchbaseContainer) isQueryKeyspacePresent(ctx context.Context, bucket func (c *CouchbaseContainer) waitForAllServicesEnabled(ctx context.Context, bucket bucket) error { err := wait.ForHTTP("/pools/default/b/"+bucket.name). WithPort(MGMT_PORT). - WithBasicCredentials(c.config.username, c.config.password). + WithBasicAuth(c.config.username, c.config.password). WithStatusCodeMatcher(func(status int) bool { return status == http.StatusOK }). From a9217292f27c14bbf89e001a8ee8bb00ba6d9526 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Tue, 28 Feb 2023 22:42:51 +0300 Subject: [PATCH 20/40] add test for community edition --- modules/couchbase/couchbase_test.go | 67 +++++++++++++++++++++++++++-- modules/couchbase/go.mod | 8 ++-- modules/couchbase/go.sum | 13 +++--- 3 files changed, 74 insertions(+), 14 deletions(-) diff --git a/modules/couchbase/couchbase_test.go b/modules/couchbase/couchbase_test.go index d820cf4207..44312a53cd 100644 --- a/modules/couchbase/couchbase_test.go +++ b/modules/couchbase/couchbase_test.go @@ -8,11 +8,40 @@ import ( "github.com/couchbase/gocb/v2" ) -func TestCouchbase(t *testing.T) { +const ( + enterpriseEdition = "couchbase:enterprise-7.1.3" + communityEdition = "couchbase:community-7.1.1" +) + +func TestCouchbaseWithCommunityContainer(t *testing.T) { + ctx := context.Background() + + bucketName := "testBucket" + container, err := StartContainer(ctx, WithImageName(communityEdition), WithBucket(NewBucket(bucketName))) + if err != nil { + t.Fatal(err) + } + + // Clean up the container after the test is complete + t.Cleanup(func() { + if err := container.Terminate(ctx); err != nil { + t.Fatalf("failed to terminate container: %s", err) + } + }) + + cluster, err := connectCluster(ctx, container) + if err != nil { + t.Fatalf("could not connect couchbase: %s", err) + } + + testBucketUsage(t, cluster.Bucket(bucketName)) +} + +func TestCouchbaseWithEnterpriseContainer(t *testing.T) { ctx := context.Background() bucketName := "testBucket" - container, err := StartContainer(ctx, WithImageName("couchbase:7.1.3"), WithBucket(NewBucket(bucketName))) + container, err := StartContainer(ctx, WithImageName(enterpriseEdition), WithBucket(NewBucket(bucketName))) if err != nil { t.Fatal(err) } @@ -29,9 +58,39 @@ func TestCouchbase(t *testing.T) { t.Fatalf("could not connect couchbase: %s", err) } - bucket := cluster.Bucket(bucketName) + testBucketUsage(t, cluster.Bucket(bucketName)) +} + +func TestAnalyticsServiceWithCommunityContainer(t *testing.T) { + ctx := context.Background() + + bucketName := "testBucket" + _, err := StartContainer(ctx, + WithImageName(communityEdition), + WithAnalyticsService(), + WithBucket(NewBucket(bucketName))) + + if err == nil { + t.Errorf("Expected error to be [%v] , got nil", err) + } +} + +func TestEventingServiceWithCommunityContainer(t *testing.T) { + ctx := context.Background() + + bucketName := "testBucket" + _, err := StartContainer(ctx, + WithImageName(communityEdition), + WithAnalyticsService(), + WithBucket(NewBucket(bucketName))) + + if err == nil { + t.Errorf("Expected error to be [%v] , got nil", err) + } +} - err = bucket.WaitUntilReady(5*time.Second, nil) +func testBucketUsage(t *testing.T, bucket *gocb.Bucket) { + err := bucket.WaitUntilReady(5*time.Second, nil) if err != nil { t.Fatalf("could not connect bucket: %s", err) } diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod index 66a8840c6f..f8e0a60fd1 100644 --- a/modules/couchbase/go.mod +++ b/modules/couchbase/go.mod @@ -14,11 +14,11 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/containerd/containerd v1.6.17 // indirect + github.com/containerd/containerd v1.6.18 // indirect github.com/couchbase/gocbcore/v10 v10.2.1 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/docker v23.0.0+incompatible // indirect + github.com/docker/docker v23.0.1+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect @@ -43,10 +43,10 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect + golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.5.0 // indirect - golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect + golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect google.golang.org/grpc v1.47.0 // indirect diff --git a/modules/couchbase/go.sum b/modules/couchbase/go.sum index b66dc76977..0d142343ea 100644 --- a/modules/couchbase/go.sum +++ b/modules/couchbase/go.sum @@ -21,8 +21,8 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.6.17 h1:XDnJIeJW0cLf6v7/+N+6L9kGrChHeXekZp2VHu6OpiY= -github.com/containerd/containerd v1.6.17/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw= +github.com/containerd/containerd v1.6.18 h1:qZbsLvmyu+Vlty0/Ex5xc0z2YtKpIsb5n45mAMI+2Ns= +github.com/containerd/containerd v1.6.18/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/couchbase/gocb/v2 v2.6.1 h1:2/ACkqvy/PPp9hd/B9f8N4sUGVauqFOuVWoOgpdYA7U= @@ -155,8 +155,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -197,8 +197,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo= -golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -241,8 +241,9 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= From effbe269e4cedef317109fedbe837c8a71755a51 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 2 Mar 2023 22:13:30 +0300 Subject: [PATCH 21/40] fix eventing service with community container test --- modules/couchbase/couchbase_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/couchbase/couchbase_test.go b/modules/couchbase/couchbase_test.go index 44312a53cd..017fa37547 100644 --- a/modules/couchbase/couchbase_test.go +++ b/modules/couchbase/couchbase_test.go @@ -81,7 +81,7 @@ func TestEventingServiceWithCommunityContainer(t *testing.T) { bucketName := "testBucket" _, err := StartContainer(ctx, WithImageName(communityEdition), - WithAnalyticsService(), + WithEventingService(), WithBucket(NewBucket(bucketName))) if err == nil { From 5b59b51be7f0a0060e5dcc8ac28edef7105b5ce7 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 2 Mar 2023 22:14:02 +0300 Subject: [PATCH 22/40] update depandabot.yml and go.mod --- .github/dependabot.yml | 6 ++++++ modules/couchbase/go.mod | 2 +- modules/couchbase/go.sum | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1ec44b7968..880ae59c81 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -24,6 +24,12 @@ updates: interval: monthly open-pull-requests-limit: 3 rebase-strategy: disabled + - package-ecosystem: gomod + directory: /modules/couchbase + schedule: + interval: monthly + open-pull-requests-limit: 3 + rebase-strategy: disabled - package-ecosystem: gomod directory: /examples/datastore schedule: diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod index f8e0a60fd1..1347f830a3 100644 --- a/modules/couchbase/go.mod +++ b/modules/couchbase/go.mod @@ -14,7 +14,7 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/containerd/containerd v1.6.18 // indirect + github.com/containerd/containerd v1.6.19 // indirect github.com/couchbase/gocbcore/v10 v10.2.1 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect diff --git a/modules/couchbase/go.sum b/modules/couchbase/go.sum index 0d142343ea..375207c2ef 100644 --- a/modules/couchbase/go.sum +++ b/modules/couchbase/go.sum @@ -5,7 +5,7 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg6 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/hcsshim v0.9.6 h1:VwnDOgLeoi2du6dAznfmspNqTiwczvjv4K7NxuY9jsY= +github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/bfg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= @@ -21,8 +21,8 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.6.18 h1:qZbsLvmyu+Vlty0/Ex5xc0z2YtKpIsb5n45mAMI+2Ns= -github.com/containerd/containerd v1.6.18/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw= +github.com/containerd/containerd v1.6.19 h1:F0qgQPrG0P2JPgwpxWxYavrVeXAG0ezUIB9Z/4FTUAU= +github.com/containerd/containerd v1.6.19/go.mod h1:HZCDMn4v/Xl2579/MvtOC2M206i+JJ6VxFWU/NetrGY= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/couchbase/gocb/v2 v2.6.1 h1:2/ACkqvy/PPp9hd/B9f8N4sUGVauqFOuVWoOgpdYA7U= From 2ed206a5c126f9ef25f8145b59b3994f687cf089 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 2 Mar 2023 22:43:44 +0300 Subject: [PATCH 23/40] update couchbase doc --- docs/modules/couchbase.md | 43 +++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/docs/modules/couchbase.md b/docs/modules/couchbase.md index bf3492c926..adc9fc450e 100644 --- a/docs/modules/couchbase.md +++ b/docs/modules/couchbase.md @@ -1,9 +1,40 @@ # Couchbase - -[Creating a Couchbase container](../../modules/couchbase/couchbase.go) - + - -[Test for a Couchbase container](../../modules/couchbase/couchbase_test.go) - +Testcontainers module for Couchbase. [Couchbase](https://www.couchbase.com/) is a document oriented NoSQL database. + +## Adding this module to your project dependencies + +Please run the following command to add the Couchbase module to your Go dependencies: + +``` +go get github.com/testcontainers/testcontainers-go/modules/couchbase +``` + +## Usage example + +1. The **StartContainer** function is the main entry point to create a new CouchbaseContainer instance. +It takes a context and zero or more Option values to configure the container. +It creates a new container instance, initializes the couchbase cluster, and creates buckets. +If successful, it returns the **CouchbaseContainer** instance. +```go +container, err := couchbase.StartContainer(ctx, + WithImageName("couchbase:community-7.1.1"), + WithBucket(NewBucket(bucketName))) +``` +2. The **ConnectionString** method returns the connection string to connect to the Couchbase container instance. +It returns a string with the format `couchbase://:`. +The **Username** method returns the username of the Couchbase administrator. +The **Password** method returns the password of the Couchbase administrator. +```go +connectionString, err := container.ConnectionString(ctx) +if err != nil { + return nil, err +} + +cluster, err := gocb.Connect(connectionString, gocb.ClusterOptions{ + Username: container.Username(), + Password: container.Password(), +}) +``` \ No newline at end of file From 23b17e0d4dc92245c10f014dbc618b04b146ae07 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Fri, 3 Mar 2023 09:43:53 +0300 Subject: [PATCH 24/40] reorder modules couchbase dependabot.yml --- .github/dependabot.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 880ae59c81..72ed717132 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -24,12 +24,6 @@ updates: interval: monthly open-pull-requests-limit: 3 rebase-strategy: disabled - - package-ecosystem: gomod - directory: /modules/couchbase - schedule: - interval: monthly - open-pull-requests-limit: 3 - rebase-strategy: disabled - package-ecosystem: gomod directory: /examples/datastore schedule: @@ -108,6 +102,12 @@ updates: interval: monthly open-pull-requests-limit: 3 rebase-strategy: disabled + - package-ecosystem: gomod + directory: /modules/couchbase + schedule: + interval: monthly + open-pull-requests-limit: 3 + rebase-strategy: disabled - package-ecosystem: gomod directory: /modules/localstack schedule: From d86893a7490d945f068294a99c6707e53a18ae84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alihan=20Do=C4=9Fu=C5=9F=20Yal=C3=A7=C4=B1n?= Date: Tue, 7 Mar 2023 21:04:07 +0300 Subject: [PATCH 25/40] Update modules/couchbase/go.mod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Manuel de la Peña --- modules/couchbase/go.mod | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod index 1347f830a3..1ad38eeb4b 100644 --- a/modules/couchbase/go.mod +++ b/modules/couchbase/go.mod @@ -55,6 +55,5 @@ require ( ) replace ( - github.com/docker/docker => github.com/docker/docker v20.10.3-0.20221013203545-33ab36d6b304+incompatible // 22.06 branch github.com/testcontainers/testcontainers-go => ../.. ) From e784d0b5108a15b30d2a575c6e3c99c220eb4eb3 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Tue, 7 Mar 2023 21:07:09 +0300 Subject: [PATCH 26/40] add comments for public methods --- modules/couchbase/couchbase.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index bff545ebd8..2331e7f695 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -87,6 +87,8 @@ func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, e return &couchbaseContainer, nil } +// ConnectionString returns the connection string to connect to the Couchbase container instance. +// It returns a string with the format couchbase://: func (c *CouchbaseContainer) ConnectionString(ctx context.Context) (string, error) { host, err := c.Host(ctx) if err != nil { @@ -101,10 +103,12 @@ func (c *CouchbaseContainer) ConnectionString(ctx context.Context) (string, erro return fmt.Sprintf("couchbase://%s:%d", host, port.Int()), nil } +// Username returns the username of the Couchbase administrator. func (c *CouchbaseContainer) Username() string { return c.config.username } +// Password returns the password of the Couchbase administrator. func (c *CouchbaseContainer) Password() string { return c.config.password } From c596691fcd6b971586acb454d8f94e1a7bb680a2 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Wed, 8 Mar 2023 22:02:21 +0300 Subject: [PATCH 27/40] add option for index storage mode --- modules/couchbase/couchbase.go | 18 +++++++++++------- modules/couchbase/go.mod | 7 +++---- modules/couchbase/go.sum | 10 ++++++---- modules/couchbase/options.go | 19 +++++++++++++------ modules/couchbase/storage_mode.go | 9 +++++++++ 5 files changed, 42 insertions(+), 21 deletions(-) create mode 100644 modules/couchbase/storage_mode.go diff --git a/modules/couchbase/couchbase.go b/modules/couchbase/couchbase.go index 2331e7f695..6ac6586d8a 100644 --- a/modules/couchbase/couchbase.go +++ b/modules/couchbase/couchbase.go @@ -51,10 +51,11 @@ type CouchbaseContainer struct { // StartContainer creates an instance of the Couchbase container type func StartContainer(ctx context.Context, opts ...Option) (*CouchbaseContainer, error) { config := &Config{ - enabledServices: []service{kv, query, search, index}, - username: "Administrator", - password: "password", - imageName: "couchbase:6.5.1", + enabledServices: []service{kv, query, search, index}, + username: "Administrator", + password: "password", + imageName: "couchbase:6.5.1", + indexStorageMode: MemoryOptimized, } for _, opt := range opts { @@ -285,13 +286,16 @@ func (c *CouchbaseContainer) configureExternalPorts(ctx context.Context) error { } func (c *CouchbaseContainer) configureIndexer(ctx context.Context) error { - storageMode := "forestdb" if c.config.isEnterprise { - storageMode = "memory_optimized" + if c.config.indexStorageMode == ForestDB { + c.config.indexStorageMode = MemoryOptimized + } + } else { + c.config.indexStorageMode = ForestDB } body := map[string]string{ - "storageMode": storageMode, + "storageMode": string(c.config.indexStorageMode), } _, err := c.doHttpRequest(ctx, MGMT_PORT, "/settings/indexes", http.MethodPost, body, true) diff --git a/modules/couchbase/go.mod b/modules/couchbase/go.mod index 1ad38eeb4b..912786df16 100644 --- a/modules/couchbase/go.mod +++ b/modules/couchbase/go.mod @@ -16,6 +16,7 @@ require ( github.com/Microsoft/go-winio v0.5.2 // indirect github.com/containerd/containerd v1.6.19 // indirect github.com/couchbase/gocbcore/v10 v10.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/docker v23.0.1+incompatible // indirect @@ -45,7 +46,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect @@ -54,6 +55,4 @@ require ( gotest.tools/v3 v3.4.0 // indirect ) -replace ( - github.com/testcontainers/testcontainers-go => ../.. -) +replace github.com/testcontainers/testcontainers-go => ../.. diff --git a/modules/couchbase/go.sum b/modules/couchbase/go.sum index 375207c2ef..f459f9173c 100644 --- a/modules/couchbase/go.sum +++ b/modules/couchbase/go.sum @@ -31,6 +31,8 @@ github.com/couchbase/gocbcore/v10 v10.2.1 h1:C5zXZUWdKrE2hncDBdDLRoKXNaVc7BYrn6J github.com/couchbase/gocbcore/v10 v10.2.1/go.mod h1:Y3S2HKwqDDcsOXdsB5YRtd2wn5ADnOQwT7G00vVylh4= github.com/couchbaselabs/gocaves/client v0.0.0-20221010100422-25779db8de05 h1:A3GRyDjp5MhqHxrGB0Hl95cCuA70Ovquy26kAJAAeZ0= github.com/couchbaselabs/gocaves/client v0.0.0-20221010100422-25779db8de05/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY= +github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= +github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= @@ -41,8 +43,8 @@ github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v20.10.3-0.20221013203545-33ab36d6b304+incompatible h1:ieHXawdo9MXKnRkKuVWEfEN3PDQUqIjz/T8vMfIaHkM= -github.com/docker/docker v20.10.3-0.20221013203545-33ab36d6b304+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY= +github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -238,8 +240,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= diff --git a/modules/couchbase/options.go b/modules/couchbase/options.go index 074bf1e88b..4da15c50e8 100644 --- a/modules/couchbase/options.go +++ b/modules/couchbase/options.go @@ -3,12 +3,13 @@ package couchbase type Option func(*Config) type Config struct { - enabledServices []service - username string - password string - isEnterprise bool - buckets []bucket - imageName string + enabledServices []service + username string + password string + isEnterprise bool + buckets []bucket + imageName string + indexStorageMode indexStorageMode } func WithEventingService() Option { @@ -41,3 +42,9 @@ func WithImageName(imageName string) Option { c.imageName = imageName } } + +func WithIndexStorageMode(indexStorageMode indexStorageMode) Option { + return func(c *Config) { + c.indexStorageMode = indexStorageMode + } +} diff --git a/modules/couchbase/storage_mode.go b/modules/couchbase/storage_mode.go new file mode 100644 index 0000000000..86920c8b9a --- /dev/null +++ b/modules/couchbase/storage_mode.go @@ -0,0 +1,9 @@ +package couchbase + +type indexStorageMode string + +const ( + MemoryOptimized indexStorageMode = "memory_optimized" + Plasma indexStorageMode = "plasma" + ForestDB indexStorageMode = "forestdb" +) From 7b65ad082688d2eea16beb1b6dab98693b30ac0d Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 9 Mar 2023 09:39:47 +0300 Subject: [PATCH 28/40] add comments for index storage modes --- modules/couchbase/storage_mode.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/couchbase/storage_mode.go b/modules/couchbase/storage_mode.go index 86920c8b9a..97d521ae3d 100644 --- a/modules/couchbase/storage_mode.go +++ b/modules/couchbase/storage_mode.go @@ -1,9 +1,22 @@ package couchbase +// The storage mode to be used for all global secondary indexes in the cluster. +// Please note: "plasma" and "memory optimized" are options in the Enterprise Edition of Couchbase Server. If you are +// using the Community Edition, the only value allowed is forestdb. type indexStorageMode string const ( + // MemoryOptimized sets the cluster-wide index storage mode to use memory optimized global + // secondary indexes which can perform index maintenance and index scan faster at in-memory speeds. + // This is the default value for the testcontainers couchbase implementation. MemoryOptimized indexStorageMode = "memory_optimized" - Plasma indexStorageMode = "plasma" - ForestDB indexStorageMode = "forestdb" + + // Plasma sets the cluster-wide index storage mode to use the Plasma storage engine, + // which can utilize both memory and persistent storage for index maintenance and index scans. + Plasma indexStorageMode = "plasma" + + // ForestDB sets the cluster-wide index storage mode to use the forestdb storage engine, + // which only utilizes persistent storage for index maintenance and scans. It is the only option available + // for the community edition. + ForestDB indexStorageMode = "forestdb" ) From dbf9679da4b86b1923b4109d13f91e52e819f593 Mon Sep 17 00:00:00 2001 From: alihanyalcin Date: Mon, 13 Mar 2023 22:14:00 +0300 Subject: [PATCH 29/40] create vault module using modulegen --- .github/dependabot.yml | 6 + .github/workflows/module-vault.yml | 46 +++++ docs/modules/vault.md | 9 + mkdocs.yml | 1 + modules/vault/Makefile | 5 + modules/vault/go.mod | 52 +++++ modules/vault/go.sum | 293 +++++++++++++++++++++++++++++ modules/vault/tools/tools.go | 11 ++ modules/vault/vault.go | 29 +++ modules/vault/vault_test.go | 24 +++ 10 files changed, 476 insertions(+) create mode 100644 .github/workflows/module-vault.yml create mode 100644 docs/modules/vault.md create mode 100644 modules/vault/Makefile create mode 100644 modules/vault/go.mod create mode 100644 modules/vault/go.sum create mode 100644 modules/vault/tools/tools.go create mode 100644 modules/vault/vault.go create mode 100644 modules/vault/vault_test.go diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e7915960c8..6e9bfd287b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -114,3 +114,9 @@ updates: interval: monthly open-pull-requests-limit: 3 rebase-strategy: disabled + - package-ecosystem: gomod + directory: /modules/vault + schedule: + interval: monthly + open-pull-requests-limit: 3 + rebase-strategy: disabled diff --git a/.github/workflows/module-vault.yml b/.github/workflows/module-vault.yml new file mode 100644 index 0000000000..372e8e7e70 --- /dev/null +++ b/.github/workflows/module-vault.yml @@ -0,0 +1,46 @@ +name: vault module pipeline + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + cancel-in-progress: true + +jobs: + test-vault: + strategy: + matrix: + go-version: [1.19.x, 1.x] + runs-on: "ubuntu-latest" + steps: + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.go-version }} + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v3 + + - name: modVerify + working-directory: ./modules/vault + run: go mod verify + + - name: modTidy + working-directory: ./modules/vault + run: make tools-tidy + + - name: gotestsum + working-directory: ./modules/vault + run: make test-unit + + - name: Run checker + run: | + ./scripts/check_environment.sh + + - name: Test Summary + uses: test-summary/action@4ee9ece4bca777a38f05c8fc578ac2007fe266f7 + with: + paths: "**/TEST-vault*.xml" + if: always() diff --git a/docs/modules/vault.md b/docs/modules/vault.md new file mode 100644 index 0000000000..a186907fcb --- /dev/null +++ b/docs/modules/vault.md @@ -0,0 +1,9 @@ +# vault + + +[Creating a vault container](../../modules/vault/vault.go) + + + +[Test for a vault container](../../modules/vault/vault_test.go) + diff --git a/mkdocs.yml b/mkdocs.yml index 93b20983cc..420f48efb4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -53,6 +53,7 @@ nav: - modules/couchbase.md - modules/localstack.md - modules/pulsar.md + - modules/vault.md - Examples: - examples/index.md - examples/bigtable.md diff --git a/modules/vault/Makefile b/modules/vault/Makefile new file mode 100644 index 0000000000..39e1ff6531 --- /dev/null +++ b/modules/vault/Makefile @@ -0,0 +1,5 @@ +include ../../commons-test.mk + +.PHONY: test +test: + $(MAKE) test-vault diff --git a/modules/vault/go.mod b/modules/vault/go.mod new file mode 100644 index 0000000000..f21086d881 --- /dev/null +++ b/modules/vault/go.mod @@ -0,0 +1,52 @@ +module github.com/testcontainers/testcontainers-go/modules/vault + +go 1.19 + +require ( + github.com/testcontainers/testcontainers-go v0.19.0 + gotest.tools/gotestsum v1.9.0 +) + +require ( + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Microsoft/go-winio v0.5.2 // indirect + github.com/cenkalti/backoff/v4 v4.2.0 // indirect + github.com/containerd/containerd v1.6.19 // indirect + github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/dnephin/pflag v1.0.7 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/docker/docker v23.0.1+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/klauspost/compress v1.15.9 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/moby/patternmatcher v0.5.0 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc2 // indirect + github.com/opencontainers/runc v1.1.3 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/term v0.5.0 // indirect + golang.org/x/tools v0.1.12 // indirect + google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect + google.golang.org/grpc v1.47.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect + gotest.tools/v3 v3.4.0 // indirect +) + +replace github.com/testcontainers/testcontainers-go => ../.. diff --git a/modules/vault/go.sum b/modules/vault/go.sum new file mode 100644 index 0000000000..ba9bb5d12a --- /dev/null +++ b/modules/vault/go.sum @@ -0,0 +1,293 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/bfg= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= +github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.6.19 h1:F0qgQPrG0P2JPgwpxWxYavrVeXAG0ezUIB9Z/4FTUAU= +github.com/containerd/containerd v1.6.19/go.mod h1:HZCDMn4v/Xl2579/MvtOC2M206i+JJ6VxFWU/NetrGY= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= +github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= +github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY= +github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= +github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f h1:J/7hjLaHLD7epG0m6TBMGmp4NQ+ibBYLfeyJWdAIFLA= +github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f/go.mod h1:15ce4BGCFxt7I5NQKT+HV0yEDxmf6fSysfEDiVo3zFM= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= +github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= +github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad h1:kqrS+lhvaMHCxul6sKQvKJ8nAAhlVItmZV822hYFH/U= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gotest.tools/gotestsum v1.9.0 h1:Jbo/0k/sIOXIJu51IZxEAt27n77xspFEfL6SqKUR72A= +gotest.tools/gotestsum v1.9.0/go.mod h1:6JHCiN6TEjA7Kaz23q1bH0e2Dc3YJjDUZ0DmctFZf+w= +gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/modules/vault/tools/tools.go b/modules/vault/tools/tools.go new file mode 100644 index 0000000000..d83700ca87 --- /dev/null +++ b/modules/vault/tools/tools.go @@ -0,0 +1,11 @@ +//go:build tools +// +build tools + +// This package contains the tool dependencies of the vault module. + +package tools + +import ( + // Register gotestsum for pinning version + _ "gotest.tools/gotestsum" +) diff --git a/modules/vault/vault.go b/modules/vault/vault.go new file mode 100644 index 0000000000..3339361d22 --- /dev/null +++ b/modules/vault/vault.go @@ -0,0 +1,29 @@ +package vault + +import ( + "context" + + "github.com/testcontainers/testcontainers-go" +) + +// vaultContainer represents the vault container type used in the module +type vaultContainer struct { + testcontainers.Container +} + +// StartContainer creates an instance of the vault container type +func StartContainer(ctx context.Context) (*vaultContainer, error) { + req := testcontainers.ContainerRequest{ + Image: "vault:latest", + } + + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + + return &vaultContainer{Container: container}, nil +} diff --git a/modules/vault/vault_test.go b/modules/vault/vault_test.go new file mode 100644 index 0000000000..8a8bcf7cdb --- /dev/null +++ b/modules/vault/vault_test.go @@ -0,0 +1,24 @@ +package vault + +import ( + "context" + "testing" +) + +func TestVault(t *testing.T) { + ctx := context.Background() + + container, err := StartContainer(ctx) + if err != nil { + t.Fatal(err) + } + + // Clean up the container after the test is complete + t.Cleanup(func() { + if err := container.Terminate(ctx); err != nil { + t.Fatalf("failed to terminate container: %s", err) + } + }) + + // perform assertions +} From 29535b16cd07f1ec0dff122c6726e7c8277f8cab Mon Sep 17 00:00:00 2001 From: alihanyalcin Date: Mon, 13 Mar 2023 23:05:41 +0300 Subject: [PATCH 30/40] add vault config options --- modules/vault/log_level.go | 14 ++++++++ modules/vault/options.go | 66 ++++++++++++++++++++++++++++++++++++++ modules/vault/vault.go | 15 +++++++-- 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 modules/vault/log_level.go create mode 100644 modules/vault/options.go diff --git a/modules/vault/log_level.go b/modules/vault/log_level.go new file mode 100644 index 0000000000..ac322feb77 --- /dev/null +++ b/modules/vault/log_level.go @@ -0,0 +1,14 @@ +package vault + +// LogLevel is a custom type that represents a logging level for the Vault +type LogLevel string + +// The following constants define the possible logging levels for the Vault +// The default log level is info +const ( + Trace LogLevel = "trace" + Debug LogLevel = "debug" + Info LogLevel = "info" + Warn LogLevel = "warn" + Error LogLevel = "err" +) diff --git a/modules/vault/options.go b/modules/vault/options.go new file mode 100644 index 0000000000..9c1d9333f2 --- /dev/null +++ b/modules/vault/options.go @@ -0,0 +1,66 @@ +package vault + +// Option is a function type for modifying a Vault configuration +type Option func(*Config) + +// Config is a struct that contains various configuration options for the Vault +type Config struct { + imageName string // The name of the Docker image to use for the Vault + token string // The root token to use for the Vault + port int // The port number to use for the Vault + secrets map[string][]string // A map of secret paths to their respective secret values + initCommands []string // A list of commands to execute on Vault initialization + logLevel LogLevel // The level of logging to use for the Vault +} + +// WithImageName is an option function that sets the Docker image name for the Vault +func WithImageName(imageName string) Option { + return func(c *Config) { + c.imageName = imageName + } +} + +// WithToken is an option function that sets the root token for the Vault +func WithToken(token string) Option { + return func(c *Config) { + c.token = token + } +} + +// WithPort is an option function that sets the port number for the Vault +func WithPort(port int) Option { + return func(c *Config) { + c.port = port + } +} + +// WithSecrets is an option function that adds a set of secrets to the Vault's configuration +func WithSecrets(path, firstSecret string, remainingSecrets ...string) Option { + return func(c *Config) { + secretList := []string{firstSecret} + + for _, secret := range remainingSecrets { + secretList = append(secretList, secret) + } + + if secrets, ok := c.secrets[path]; ok { + secretList = append(secretList, secrets...) + } + + c.secrets[path] = secretList + } +} + +// WithInitCommands is an option function that adds a set of initialization commands to the Vault's configuration +func WithInitCommands(commands ...string) Option { + return func(c *Config) { + c.initCommands = append(c.initCommands, commands...) + } +} + +// WithLogLevel is an option function that sets the logging level for the Vault +func WithLogLevel(logLevel LogLevel) Option { + return func(c *Config) { + c.logLevel = logLevel + } +} diff --git a/modules/vault/vault.go b/modules/vault/vault.go index 3339361d22..2d7b4f9df4 100644 --- a/modules/vault/vault.go +++ b/modules/vault/vault.go @@ -2,6 +2,7 @@ package vault import ( "context" + "fmt" "github.com/testcontainers/testcontainers-go" ) @@ -12,9 +13,19 @@ type vaultContainer struct { } // StartContainer creates an instance of the vault container type -func StartContainer(ctx context.Context) (*vaultContainer, error) { +func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error) { + config := &Config{ + imageName: "vault:latest", + port: 8200, + } + + for _, opt := range opts { + opt(config) + } + req := testcontainers.ContainerRequest{ - Image: "vault:latest", + Image: config.imageName, + ExposedPorts: []string{fmt.Sprintf("%d/tcp", config.port)}, } container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ From e79a857194bafd49ee2c608707ffcb214a1c36ac Mon Sep 17 00:00:00 2001 From: alihanyalcin Date: Tue, 14 Mar 2023 23:56:08 +0300 Subject: [PATCH 31/40] update container request, impl add secret and init commands --- modules/vault/vault.go | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/modules/vault/vault.go b/modules/vault/vault.go index 2d7b4f9df4..0ee933987a 100644 --- a/modules/vault/vault.go +++ b/modules/vault/vault.go @@ -3,13 +3,22 @@ package vault import ( "context" "fmt" + "io" + "strings" + "github.com/docker/docker/api/types/container" "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" +) + +const ( + errorAddSecret = "failed to add secrets %v to Vault via exec command: %w" ) // vaultContainer represents the vault container type used in the module type vaultContainer struct { testcontainers.Container + config *Config } // StartContainer creates an instance of the vault container type @@ -26,6 +35,11 @@ func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error req := testcontainers.ContainerRequest{ Image: config.imageName, ExposedPorts: []string{fmt.Sprintf("%d/tcp", config.port)}, + HostConfigModifier: func(hc *container.HostConfig) { + hc.CapAdd = []string{"IPC_LOCK"} + }, + WaitingFor: wait.ForHTTP("/v1/sys/health"), + Env: setEnv(config), } container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ @@ -38,3 +52,82 @@ func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error return &vaultContainer{Container: container}, nil } + +func (v *vaultContainer) addSecrets(ctx context.Context) error { + if len(v.config.secrets) == 0 { + return nil + } + + code, reader, err := v.Exec(ctx, buildExecCommand(v.config.secrets)) + if err != nil || code != 0 { + return fmt.Errorf(errorAddSecret, v.config.secrets, err) + } + + out, err := io.ReadAll(reader) + if err != nil { + return fmt.Errorf(errorAddSecret, v.config.secrets, err) + } + + if !strings.Contains(string(out), "Success") { + return fmt.Errorf(errorAddSecret, v.config.secrets, err) + } + + return nil +} + +func (v *vaultContainer) runInitCommands(ctx context.Context) error { + if len(v.config.initCommands) == 0 { + return nil + } + + commands := make([]string, 0, len(v.config.initCommands)) + for _, command := range v.config.initCommands { + commands = append(commands, "vault "+command) + } + fullCommand := []string{"/bin/sh", "-c", strings.Join(commands, " && ")} + + code, stdout, err := v.Exec(ctx, fullCommand) + if err != nil { + return err + } + + if code != 0 { + return fmt.Errorf("failed to execute init commands: exit code %d, stdout %s", code, stdout) + } + + return nil +} + +func buildExecCommand(secretsMap map[string][]string) []string { + var commandParts []string + + // Loop over the secrets map and build the command string + for path, secrets := range secretsMap { + commandParts = append(commandParts, "vault", "kv", "put", path) + commandParts = append(commandParts, secrets...) + commandParts = append(commandParts, "&&") + } + + if len(commandParts) > 0 { + commandParts = commandParts[:len(commandParts)-1] + } + + // Prepend the command with "/bin/sh -c" to execute the command in a shell + commandParts = append([]string{"/bin/sh", "-c"}, strings.Join(commandParts, " ")) + + return commandParts +} + +func setEnv(config *Config) map[string]string { + env := make(map[string]string) + + env["VAULT_ADDR"] = fmt.Sprintf("http://0.0.0.0:%d", config.port) + env["VAULT_LOG_LEVEL"] = string(config.logLevel) + + if config.token != "" { + env["VAULT_DEV_ROOT_TOKEN_ID"] = config.token + env["VAULT_TOKEN"] = config.token + } + + return env +} From b2322d5c4a4031747c53b284db7131293ff70be4 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 16 Mar 2023 10:33:56 +0300 Subject: [PATCH 32/40] add addSecret and runInitCommands to StartContainer --- modules/vault/options.go | 16 ++++++++++++++++ modules/vault/vault.go | 38 ++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/modules/vault/options.go b/modules/vault/options.go index 9c1d9333f2..da8b113ba8 100644 --- a/modules/vault/options.go +++ b/modules/vault/options.go @@ -1,5 +1,7 @@ package vault +import "fmt" + // Option is a function type for modifying a Vault configuration type Option func(*Config) @@ -13,6 +15,20 @@ type Config struct { logLevel LogLevel // The level of logging to use for the Vault } +func (c *Config) exportEnv() map[string]string { + env := make(map[string]string) + + env["VAULT_ADDR"] = fmt.Sprintf("http://0.0.0.0:%d", c.port) + env["VAULT_LOG_LEVEL"] = string(c.logLevel) + + if c.token != "" { + env["VAULT_DEV_ROOT_TOKEN_ID"] = c.token + env["VAULT_TOKEN"] = c.token + } + + return env +} + // WithImageName is an option function that sets the Docker image name for the Vault func WithImageName(imageName string) Option { return func(c *Config) { diff --git a/modules/vault/vault.go b/modules/vault/vault.go index 0ee933987a..5491c06bda 100644 --- a/modules/vault/vault.go +++ b/modules/vault/vault.go @@ -3,7 +3,9 @@ package vault import ( "context" "fmt" + "github.com/docker/go-connections/nat" "io" + "strconv" "strings" "github.com/docker/docker/api/types/container" @@ -24,7 +26,7 @@ type vaultContainer struct { // StartContainer creates an instance of the vault container type func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error) { config := &Config{ - imageName: "vault:latest", + imageName: "vault:1.13.0", port: 8200, } @@ -38,8 +40,8 @@ func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error HostConfigModifier: func(hc *container.HostConfig) { hc.CapAdd = []string{"IPC_LOCK"} }, - WaitingFor: wait.ForHTTP("/v1/sys/health"), - Env: setEnv(config), + WaitingFor: wait.ForHTTP("/v1/sys/health").WithPort(nat.Port(strconv.Itoa(config.port))), + Env: config.exportEnv(), } container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ @@ -50,7 +52,17 @@ func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error return nil, err } - return &vaultContainer{Container: container}, nil + v := vaultContainer{container, config} + + if err = v.addSecrets(ctx); err != nil { + return nil, err + } + + if err = v.runInitCommands(ctx); err != nil { + return nil, err + } + + return &v, nil } func (v *vaultContainer) addSecrets(ctx context.Context) error { @@ -60,6 +72,10 @@ func (v *vaultContainer) addSecrets(ctx context.Context) error { code, reader, err := v.Exec(ctx, buildExecCommand(v.config.secrets)) if err != nil || code != 0 { + return err + } + + if code != 0 { return fmt.Errorf(errorAddSecret, v.config.secrets, err) } @@ -117,17 +133,3 @@ func buildExecCommand(secretsMap map[string][]string) []string { return commandParts } - -func setEnv(config *Config) map[string]string { - env := make(map[string]string) - - env["VAULT_ADDR"] = fmt.Sprintf("http://0.0.0.0:%d", config.port) - env["VAULT_LOG_LEVEL"] = string(config.logLevel) - - if config.token != "" { - env["VAULT_DEV_ROOT_TOKEN_ID"] = config.token - env["VAULT_TOKEN"] = config.token - } - - return env -} From 32cefd3c3161bb01e6be0454c780d11d42cd1f73 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 16 Mar 2023 23:50:57 +0300 Subject: [PATCH 33/40] add tests --- modules/vault/go.mod | 26 +++++- modules/vault/go.sum | 42 ++++++++++ modules/vault/vault.go | 39 ++++----- modules/vault/vault_test.go | 156 +++++++++++++++++++++++++++++++++--- 4 files changed, 230 insertions(+), 33 deletions(-) diff --git a/modules/vault/go.mod b/modules/vault/go.mod index f21086d881..03ba218892 100644 --- a/modules/vault/go.mod +++ b/modules/vault/go.mod @@ -3,7 +3,11 @@ module github.com/testcontainers/testcontainers-go/modules/vault go 1.19 require ( + github.com/docker/docker v23.0.1+incompatible + github.com/docker/go-connections v0.4.0 + github.com/stretchr/testify v1.8.2 github.com/testcontainers/testcontainers-go v0.19.0 + github.com/tidwall/gjson v1.14.4 gotest.tools/gotestsum v1.9.0 ) @@ -13,10 +17,9 @@ require ( github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/containerd/containerd v1.6.19 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/docker v23.0.1+incompatible // indirect - github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect @@ -24,10 +27,18 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.2 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/vault-client-go v0.2.0 // indirect github.com/klauspost/compress v1.15.9 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/moby/patternmatcher v0.5.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f // indirect @@ -36,16 +47,23 @@ require ( github.com/opencontainers/image-spec v1.1.0-rc2 // indirect github.com/opencontainers/runc v1.1.3 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect + golang.org/x/mod v0.6.0 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.5.0 // indirect - golang.org/x/tools v0.1.12 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.2.0 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect google.golang.org/grpc v1.47.0 // indirect google.golang.org/protobuf v1.28.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.4.0 // indirect ) diff --git a/modules/vault/go.sum b/modules/vault/go.sum index ba9bb5d12a..8e885a7a0d 100644 --- a/modules/vault/go.sum +++ b/modules/vault/go.sum @@ -92,12 +92,30 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= +github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/vault-client-go v0.2.0 h1:Zzf5D2kj7QmBZE2ZTdril1aJlujMptPatxslTkdDF+U= +github.com/hashicorp/vault-client-go v0.2.0/go.mod h1:C9rbJeHeI1Dy/MXXd5YLrzRfAH27n6mARnhpvaW/8gk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -108,6 +126,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +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/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= @@ -132,7 +152,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -141,11 +164,22 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= @@ -158,6 +192,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -165,6 +201,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -233,6 +270,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -245,6 +284,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -280,10 +320,12 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/gotestsum v1.9.0 h1:Jbo/0k/sIOXIJu51IZxEAt27n77xspFEfL6SqKUR72A= gotest.tools/gotestsum v1.9.0/go.mod h1:6JHCiN6TEjA7Kaz23q1bH0e2Dc3YJjDUZ0DmctFZf+w= gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= diff --git a/modules/vault/vault.go b/modules/vault/vault.go index 5491c06bda..b59eb5e8f8 100644 --- a/modules/vault/vault.go +++ b/modules/vault/vault.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "github.com/docker/go-connections/nat" - "io" "strconv" "strings" @@ -13,10 +12,6 @@ import ( "github.com/testcontainers/testcontainers-go/wait" ) -const ( - errorAddSecret = "failed to add secrets %v to Vault via exec command: %w" -) - // vaultContainer represents the vault container type used in the module type vaultContainer struct { testcontainers.Container @@ -28,6 +23,7 @@ func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error config := &Config{ imageName: "vault:1.13.0", port: 8200, + secrets: map[string][]string{}, } for _, opt := range opts { @@ -65,27 +61,32 @@ func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error return &v, nil } -func (v *vaultContainer) addSecrets(ctx context.Context) error { - if len(v.config.secrets) == 0 { - return nil +func (v *vaultContainer) HttpHostAddress(ctx context.Context) (string, error) { + host, err := v.Host(ctx) + if err != nil { + return "", err } - code, reader, err := v.Exec(ctx, buildExecCommand(v.config.secrets)) - if err != nil || code != 0 { - return err + port, err := v.MappedPort(ctx, nat.Port(strconv.Itoa(v.config.port))) + if err != nil { + return "", err } - if code != 0 { - return fmt.Errorf(errorAddSecret, v.config.secrets, err) + return fmt.Sprintf("http://%s:%d", host, port.Int()), nil +} + +func (v *vaultContainer) addSecrets(ctx context.Context) error { + if len(v.config.secrets) == 0 { + return nil } - out, err := io.ReadAll(reader) + code, _, err := v.Exec(ctx, buildExecCommand(v.config.secrets)) if err != nil { - return fmt.Errorf(errorAddSecret, v.config.secrets, err) + return err } - if !strings.Contains(string(out), "Success") { - return fmt.Errorf(errorAddSecret, v.config.secrets, err) + if code != 0 { + return fmt.Errorf("failed to add secrets %v to Vault via exec command: %d", v.config.secrets, code) } return nil @@ -102,13 +103,13 @@ func (v *vaultContainer) runInitCommands(ctx context.Context) error { } fullCommand := []string{"/bin/sh", "-c", strings.Join(commands, " && ")} - code, stdout, err := v.Exec(ctx, fullCommand) + code, _, err := v.Exec(ctx, fullCommand) if err != nil { return err } if code != 0 { - return fmt.Errorf("failed to execute init commands: exit code %d, stdout %s", code, stdout) + return fmt.Errorf("failed to execute init commands: exit code %d", code) } return nil diff --git a/modules/vault/vault_test.go b/modules/vault/vault_test.go index 8a8bcf7cdb..f1052f94cd 100644 --- a/modules/vault/vault_test.go +++ b/modules/vault/vault_test.go @@ -2,23 +2,159 @@ package vault import ( "context" + "io" + "log" + "net/http" + "os" "testing" + "time" + + vaultClient "github.com/hashicorp/vault-client-go" + "github.com/hashicorp/vault-client-go/schema" + "github.com/stretchr/testify/assert" + "github.com/tidwall/gjson" ) -func TestVault(t *testing.T) { - ctx := context.Background() +const ( + token = "root-token" +) - container, err := StartContainer(ctx) +var ( + ctx = context.Background() + vault *vaultContainer +) + +func TestMain(m *testing.M) { + var err error + vault, err = StartContainer(ctx, + WithToken(token), + WithSecrets("secret/test1", "foo1=bar1"), + WithSecrets("secret/test2", "foo2=bar2", "foo3=bar3"), + WithInitCommands("secrets enable transit", "write -f transit/keys/my-key")) if err != nil { - t.Fatal(err) + log.Fatal(err) + } + + c := m.Run() + + // Clean up the vault after the test is complete + if err = vault.Terminate(ctx); err != nil { + log.Fatalf("failed to terminate vault: %s", err) } - // Clean up the container after the test is complete - t.Cleanup(func() { - if err := container.Terminate(ctx); err != nil { - t.Fatalf("failed to terminate container: %s", err) - } + os.Exit(c) +} + +func TestVaultFirstSecretPathWithCLI(t *testing.T) { + exec, reader, err := vault.Exec(ctx, []string{"vault", "kv", "get", "-format=json", "secret/test1"}) + assert.Nil(t, err) + assert.Equal(t, 0, exec) + + bytes, err := io.ReadAll(reader) + assert.Nil(t, err) + + assert.Equal(t, "bar1", gjson.Get(string(bytes), "data.data.foo1").String()) +} + +func TestVaultSecondSecretPathWithCLI(t *testing.T) { + exec, reader, err := vault.Exec(ctx, []string{"vault", "kv", "get", "-format=json", "secret/test2"}) + assert.Nil(t, err) + assert.Equal(t, 0, exec) + + bytes, err := io.ReadAll(reader) + assert.Nil(t, err) + + assert.Equal(t, "bar2", gjson.Get(string(bytes), "data.data.foo2").String()) + assert.Equal(t, "bar3", gjson.Get(string(bytes), "data.data.foo3").String()) +} + +func TestVaultFirstSecretPathWithHTTP(t *testing.T) { + hostAddress, err := vault.HttpHostAddress(ctx) + assert.Nil(t, err) + + request, _ := http.NewRequest(http.MethodGet, hostAddress+"/v1/secret/data/test1", nil) + request.Header.Add("X-Vault-Token", token) + + response, err := http.DefaultClient.Do(request) + assert.Nil(t, err) + defer response.Body.Close() + + body, err := io.ReadAll(response.Body) + assert.Nil(t, err) + + assert.Equal(t, "bar1", gjson.Get(string(body), "data.data.foo1").String()) +} + +func TestVaultSecondSecretPathWithHTTP(t *testing.T) { + hostAddress, err := vault.HttpHostAddress(ctx) + assert.Nil(t, err) + + request, _ := http.NewRequest(http.MethodGet, hostAddress+"/v1/secret/data/test2", nil) + request.Header.Add("X-Vault-Token", token) + + response, err := http.DefaultClient.Do(request) + assert.Nil(t, err) + defer response.Body.Close() + + body, err := io.ReadAll(response.Body) + assert.Nil(t, err) + + assert.Equal(t, "bar2", gjson.Get(string(body), "data.data.foo2").String()) + assert.Equal(t, "bar3", gjson.Get(string(body), "data.data.foo3").String()) +} + +func TestVaultFirstSecretPathWithClient(t *testing.T) { + hostAddress, _ := vault.HttpHostAddress(ctx) + client, err := vaultClient.New( + vaultClient.WithAddress(hostAddress), + vaultClient.WithRequestTimeout(30*time.Second), + ) + assert.Nil(t, err) + + err = client.SetToken(token) + assert.Nil(t, err) + + s, err := client.Secrets.KVv2Read(ctx, "test1") + assert.Nil(t, err) + assert.Equal(t, "bar1", s.Data["data"].(map[string]interface{})["foo1"]) +} + +func TestVaultSecondSecretPathWithClient(t *testing.T) { + hostAddress, _ := vault.HttpHostAddress(ctx) + client, err := vaultClient.New( + vaultClient.WithAddress(hostAddress), + vaultClient.WithRequestTimeout(30*time.Second), + ) + assert.Nil(t, err) + + err = client.SetToken(token) + assert.Nil(t, err) + + s, err := client.Secrets.KVv2Read(ctx, "test2") + assert.Nil(t, err) + assert.Equal(t, "bar2", s.Data["data"].(map[string]interface{})["foo2"]) + assert.Equal(t, "bar3", s.Data["data"].(map[string]interface{})["foo3"]) +} + +func TestVaultWriteSecretWithClient(t *testing.T) { + hostAddress, _ := vault.HttpHostAddress(ctx) + client, err := vaultClient.New( + vaultClient.WithAddress(hostAddress), + vaultClient.WithRequestTimeout(30*time.Second), + ) + assert.Nil(t, err) + + err = client.SetToken(token) + assert.Nil(t, err) + + _, err = client.Secrets.KVv2Write(ctx, "test3", schema.KVv2WriteRequest{ + Data: map[string]any{ + "foo": "bar", + }, }) + assert.Nil(t, err) - // perform assertions + s, err := client.Secrets.KVv2Read(ctx, "test3") + assert.Nil(t, err) + assert.Equal(t, "bar", s.Data["data"].(map[string]interface{})["foo"]) } From 17ab67bf7f37f30f6973eb54a7ddce77727f16e4 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 16 Mar 2023 23:53:08 +0300 Subject: [PATCH 34/40] add default log level --- modules/vault/vault.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/vault/vault.go b/modules/vault/vault.go index b59eb5e8f8..b3b219e792 100644 --- a/modules/vault/vault.go +++ b/modules/vault/vault.go @@ -23,6 +23,7 @@ func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error config := &Config{ imageName: "vault:1.13.0", port: 8200, + logLevel: Info, secrets: map[string][]string{}, } From f8bbf811d5eac1f6b83482fbcd4125000c6a0467 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Sat, 18 Mar 2023 00:19:34 +0300 Subject: [PATCH 35/40] add vault doc --- docs/modules/vault.md | 32 +++++++++++++++++++++++++++++--- modules/vault/vault_test.go | 2 ++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/modules/vault.md b/docs/modules/vault.md index a186907fcb..436d48fb00 100644 --- a/docs/modules/vault.md +++ b/docs/modules/vault.md @@ -1,9 +1,35 @@ -# vault +# Vault + + +Testcontainers module for Vault. [Vault](https://www.vaultproject.io/) is an open-source tool designed for securely storing, accessing, and managing secrets and sensitive data such as passwords, certificates, API keys, and other confidential information. + +## Adding this module to your project dependencies + +Please run the following command to add the Vault module to your Go dependencies: + +``` +go get github.com/testcontainers/testcontainers-go/modules/vault +``` + +## Usage example +The **StartContainer** function is the main entry point to create a new VaultContainer instance. +It takes a context and zero or more Option values to configure the container. -[Creating a vault container](../../modules/vault/vault.go) +[Creating a Vault container](../../modules/vault/vault_test.go) inside_block:StartContainer +### Use CLI to read data from Vault container: -[Test for a vault container](../../modules/vault/vault_test.go) +[Use CLI to read data](../../modules/vault/vault_test.go) inside_block:TestVaultFirstSecretPathWithCLI + +### Use HTTP API to read data from Vault container: + +[Use HTTP API to read data](../../modules/vault/vault_test.go) inside_block:TestVaultFirstSecretPathWithHTTP + + +### Use client library to read data from Vault container: + +[Use library to read data](../../modules/vault/vault_test.go) inside_block:TestVaultFirstSecretPathWithClient + \ No newline at end of file diff --git a/modules/vault/vault_test.go b/modules/vault/vault_test.go index f1052f94cd..18c6856cb8 100644 --- a/modules/vault/vault_test.go +++ b/modules/vault/vault_test.go @@ -26,11 +26,13 @@ var ( func TestMain(m *testing.M) { var err error + // StartContainer { vault, err = StartContainer(ctx, WithToken(token), WithSecrets("secret/test1", "foo1=bar1"), WithSecrets("secret/test2", "foo2=bar2", "foo3=bar3"), WithInitCommands("secrets enable transit", "write -f transit/keys/my-key")) + // } if err != nil { log.Fatal(err) } From 0c7645e72ba5d75c0db03d1c23cd7fddd41f46cd Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Mon, 20 Mar 2023 17:18:31 +0300 Subject: [PATCH 36/40] remove options and use ContainerRequest --- modules/vault/options.go | 82 --------------------- modules/vault/vault.go | 141 ++++++++++++++---------------------- modules/vault/vault_test.go | 7 +- 3 files changed, 58 insertions(+), 172 deletions(-) delete mode 100644 modules/vault/options.go diff --git a/modules/vault/options.go b/modules/vault/options.go deleted file mode 100644 index da8b113ba8..0000000000 --- a/modules/vault/options.go +++ /dev/null @@ -1,82 +0,0 @@ -package vault - -import "fmt" - -// Option is a function type for modifying a Vault configuration -type Option func(*Config) - -// Config is a struct that contains various configuration options for the Vault -type Config struct { - imageName string // The name of the Docker image to use for the Vault - token string // The root token to use for the Vault - port int // The port number to use for the Vault - secrets map[string][]string // A map of secret paths to their respective secret values - initCommands []string // A list of commands to execute on Vault initialization - logLevel LogLevel // The level of logging to use for the Vault -} - -func (c *Config) exportEnv() map[string]string { - env := make(map[string]string) - - env["VAULT_ADDR"] = fmt.Sprintf("http://0.0.0.0:%d", c.port) - env["VAULT_LOG_LEVEL"] = string(c.logLevel) - - if c.token != "" { - env["VAULT_DEV_ROOT_TOKEN_ID"] = c.token - env["VAULT_TOKEN"] = c.token - } - - return env -} - -// WithImageName is an option function that sets the Docker image name for the Vault -func WithImageName(imageName string) Option { - return func(c *Config) { - c.imageName = imageName - } -} - -// WithToken is an option function that sets the root token for the Vault -func WithToken(token string) Option { - return func(c *Config) { - c.token = token - } -} - -// WithPort is an option function that sets the port number for the Vault -func WithPort(port int) Option { - return func(c *Config) { - c.port = port - } -} - -// WithSecrets is an option function that adds a set of secrets to the Vault's configuration -func WithSecrets(path, firstSecret string, remainingSecrets ...string) Option { - return func(c *Config) { - secretList := []string{firstSecret} - - for _, secret := range remainingSecrets { - secretList = append(secretList, secret) - } - - if secrets, ok := c.secrets[path]; ok { - secretList = append(secretList, secrets...) - } - - c.secrets[path] = secretList - } -} - -// WithInitCommands is an option function that adds a set of initialization commands to the Vault's configuration -func WithInitCommands(commands ...string) Option { - return func(c *Config) { - c.initCommands = append(c.initCommands, commands...) - } -} - -// WithLogLevel is an option function that sets the logging level for the Vault -func WithLogLevel(logLevel LogLevel) Option { - return func(c *Config) { - c.logLevel = logLevel - } -} diff --git a/modules/vault/vault.go b/modules/vault/vault.go index b3b219e792..66da2afe2a 100644 --- a/modules/vault/vault.go +++ b/modules/vault/vault.go @@ -3,42 +3,42 @@ package vault import ( "context" "fmt" - "github.com/docker/go-connections/nat" - "strconv" + "github.com/testcontainers/testcontainers-go/wait" "strings" "github.com/docker/docker/api/types/container" "github.com/testcontainers/testcontainers-go" - "github.com/testcontainers/testcontainers-go/wait" ) +const ( + defaultPort = "8200" + defaultImageName = "vault:1.13.0" +) + +// ContainerOptions is a function that can be used to configure the Vault container +type ContainerOptions func(req *testcontainers.ContainerRequest) + // vaultContainer represents the vault container type used in the module type vaultContainer struct { testcontainers.Container - config *Config } // StartContainer creates an instance of the vault container type -func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error) { - config := &Config{ - imageName: "vault:1.13.0", - port: 8200, - logLevel: Info, - secrets: map[string][]string{}, - } - - for _, opt := range opts { - opt(config) - } - +func StartContainer(ctx context.Context, opts ...ContainerOptions) (*vaultContainer, error) { req := testcontainers.ContainerRequest{ - Image: config.imageName, - ExposedPorts: []string{fmt.Sprintf("%d/tcp", config.port)}, + Image: defaultImageName, + ExposedPorts: []string{defaultPort + "/tcp"}, HostConfigModifier: func(hc *container.HostConfig) { hc.CapAdd = []string{"IPC_LOCK"} }, - WaitingFor: wait.ForHTTP("/v1/sys/health").WithPort(nat.Port(strconv.Itoa(config.port))), - Env: config.exportEnv(), + WaitingFor: wait.ForHTTP("/v1/sys/health").WithPort(defaultPort), + Env: map[string]string{ + "VAULT_ADDR": "http://0.0.0.0:" + defaultPort, + }, + } + + for _, opt := range opts { + opt(&req) } container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ @@ -49,89 +49,56 @@ func StartContainer(ctx context.Context, opts ...Option) (*vaultContainer, error return nil, err } - v := vaultContainer{container, config} - - if err = v.addSecrets(ctx); err != nil { - return nil, err - } - - if err = v.runInitCommands(ctx); err != nil { - return nil, err - } - - return &v, nil + return &vaultContainer{container}, nil } -func (v *vaultContainer) HttpHostAddress(ctx context.Context) (string, error) { - host, err := v.Host(ctx) - if err != nil { - return "", err - } - - port, err := v.MappedPort(ctx, nat.Port(strconv.Itoa(v.config.port))) - if err != nil { - return "", err +// WithImageName is an option function that sets the Docker image name for the Vault +func WithImageName(imageName string) ContainerOptions { + return func(req *testcontainers.ContainerRequest) { + req.Image = imageName } - - return fmt.Sprintf("http://%s:%d", host, port.Int()), nil } -func (v *vaultContainer) addSecrets(ctx context.Context) error { - if len(v.config.secrets) == 0 { - return nil +// WithToken is a container option function that sets the root token for the Vault +func WithToken(token string) ContainerOptions { + return func(req *testcontainers.ContainerRequest) { + req.Env["VAULT_DEV_ROOT_TOKEN_ID"] = token + req.Env["VAULT_TOKEN"] = token } - - code, _, err := v.Exec(ctx, buildExecCommand(v.config.secrets)) - if err != nil { - return err - } - - if code != 0 { - return fmt.Errorf("failed to add secrets %v to Vault via exec command: %d", v.config.secrets, code) - } - - return nil } -func (v *vaultContainer) runInitCommands(ctx context.Context) error { - if len(v.config.initCommands) == 0 { - return nil - } - - commands := make([]string, 0, len(v.config.initCommands)) - for _, command := range v.config.initCommands { - commands = append(commands, "vault "+command) +// WithLogLevel is an option function that sets the logging level for the Vault +func WithLogLevel(logLevel LogLevel) ContainerOptions { + return func(req *testcontainers.ContainerRequest) { + req.Env["VAULT_LOG_LEVEL"] = string(logLevel) } - fullCommand := []string{"/bin/sh", "-c", strings.Join(commands, " && ")} +} - code, _, err := v.Exec(ctx, fullCommand) - if err != nil { - return err - } +// WithInitCommand is an option function that adds a set of initialization commands to the Vault's configuration +func WithInitCommand(commands ...string) ContainerOptions { + return func(req *testcontainers.ContainerRequest) { + commandsList := make([]string, 0, len(commands)) + for _, command := range commands { + commandsList = append(commandsList, "vault "+command) + } + cmd := []string{"/bin/sh", "-c", strings.Join(commandsList, " && ")} - if code != 0 { - return fmt.Errorf("failed to execute init commands: exit code %d", code) + req.WaitingFor = wait.ForAll(req.WaitingFor, wait.ForExec(cmd)) } - - return nil } -func buildExecCommand(secretsMap map[string][]string) []string { - var commandParts []string - - // Loop over the secrets map and build the command string - for path, secrets := range secretsMap { - commandParts = append(commandParts, "vault", "kv", "put", path) - commandParts = append(commandParts, secrets...) - commandParts = append(commandParts, "&&") +// HttpHostAddress returns the http host address of Vault. +// It returns a string with the format http://: +func (v *vaultContainer) HttpHostAddress(ctx context.Context) (string, error) { + host, err := v.Host(ctx) + if err != nil { + return "", err } - if len(commandParts) > 0 { - commandParts = commandParts[:len(commandParts)-1] + port, err := v.MappedPort(ctx, defaultPort) + if err != nil { + return "", err } - // Prepend the command with "/bin/sh -c" to execute the command in a shell - commandParts = append([]string{"/bin/sh", "-c"}, strings.Join(commandParts, " ")) - - return commandParts + return fmt.Sprintf("http://%s:%d", host, port.Int()), nil } diff --git a/modules/vault/vault_test.go b/modules/vault/vault_test.go index 18c6856cb8..624dc988bf 100644 --- a/modules/vault/vault_test.go +++ b/modules/vault/vault_test.go @@ -28,10 +28,11 @@ func TestMain(m *testing.M) { var err error // StartContainer { vault, err = StartContainer(ctx, + WithLogLevel(Debug), WithToken(token), - WithSecrets("secret/test1", "foo1=bar1"), - WithSecrets("secret/test2", "foo2=bar2", "foo3=bar3"), - WithInitCommands("secrets enable transit", "write -f transit/keys/my-key")) + WithInitCommand("secrets enable transit", "write -f transit/keys/my-key"), + WithInitCommand("kv put secret/test1 foo1=bar1"), + WithInitCommand("kv put secret/test2 foo2=bar2 foo3=bar3")) // } if err != nil { log.Fatal(err) From 06c286cbfbf3c91237a9c03e3d05d5debf6b13b3 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Mon, 20 Mar 2023 22:18:26 +0300 Subject: [PATCH 37/40] update docs and tests, export vault container type --- docs/modules/vault.md | 34 ++++++++++++++-- modules/vault/vault.go | 10 ++--- modules/vault/vault_test.go | 81 +++++++++++-------------------------- 3 files changed, 59 insertions(+), 66 deletions(-) diff --git a/docs/modules/vault.md b/docs/modules/vault.md index 436d48fb00..372da297a3 100644 --- a/docs/modules/vault.md +++ b/docs/modules/vault.md @@ -21,15 +21,43 @@ It takes a context and zero or more Option values to configure the container. ### Use CLI to read data from Vault container: -[Use CLI to read data](../../modules/vault/vault_test.go) inside_block:TestVaultFirstSecretPathWithCLI +[Use CLI to read data](../../modules/vault/vault_test.go) inside_block:TestVaultGetSecretPathWithCLI ### Use HTTP API to read data from Vault container: -[Use HTTP API to read data](../../modules/vault/vault_test.go) inside_block:TestVaultFirstSecretPathWithHTTP +[Use HTTP API to read data](../../modules/vault/vault_test.go) inside_block:TestVaultGetSecretPathWithHTTP ### Use client library to read data from Vault container: -[Use library to read data](../../modules/vault/vault_test.go) inside_block:TestVaultFirstSecretPathWithClient +[Use library to read data](../../modules/vault/vault_test.go) inside_block:TestVaultGetSecretPathWithClient + + +## Container Options + +You can set below options to create Vault container. + +### Image +If you need to set a different Vault image, you can use the `WithImageName`. Default image name is `vault:1.13.0` + +[Set image name](../../modules/vault/vault_test.go) inside_block:WithImageName + + +### Token +If you need to add token authentication, you can use the `WithToken`. + +[Add token authentication](../../modules/vault/vault_test.go) inside_block:WithToken + + +### Log Level +If you need to change log level, you can use the `WithLogLevel`. Default log level is `info` + +[Change log level](../../modules/vault/vault_test.go) inside_block:WithLogLevel + + +### Command +If you need to run vault command in the container, you can use the `WithInitCommand`. + +[Run init command](../../modules/vault/vault_test.go) inside_block:WithInitCommand \ No newline at end of file diff --git a/modules/vault/vault.go b/modules/vault/vault.go index 66da2afe2a..9d281d6b3f 100644 --- a/modules/vault/vault.go +++ b/modules/vault/vault.go @@ -18,13 +18,13 @@ const ( // ContainerOptions is a function that can be used to configure the Vault container type ContainerOptions func(req *testcontainers.ContainerRequest) -// vaultContainer represents the vault container type used in the module -type vaultContainer struct { +// VaultContainer represents the vault container type used in the module +type VaultContainer struct { testcontainers.Container } // StartContainer creates an instance of the vault container type -func StartContainer(ctx context.Context, opts ...ContainerOptions) (*vaultContainer, error) { +func StartContainer(ctx context.Context, opts ...ContainerOptions) (*VaultContainer, error) { req := testcontainers.ContainerRequest{ Image: defaultImageName, ExposedPorts: []string{defaultPort + "/tcp"}, @@ -49,7 +49,7 @@ func StartContainer(ctx context.Context, opts ...ContainerOptions) (*vaultContai return nil, err } - return &vaultContainer{container}, nil + return &VaultContainer{container}, nil } // WithImageName is an option function that sets the Docker image name for the Vault @@ -89,7 +89,7 @@ func WithInitCommand(commands ...string) ContainerOptions { // HttpHostAddress returns the http host address of Vault. // It returns a string with the format http://: -func (v *vaultContainer) HttpHostAddress(ctx context.Context) (string, error) { +func (v *VaultContainer) HttpHostAddress(ctx context.Context) (string, error) { host, err := v.Host(ctx) if err != nil { return "", err diff --git a/modules/vault/vault_test.go b/modules/vault/vault_test.go index 624dc988bf..4d2551f35f 100644 --- a/modules/vault/vault_test.go +++ b/modules/vault/vault_test.go @@ -1,4 +1,4 @@ -package vault +package vault_test import ( "context" @@ -12,6 +12,7 @@ import ( vaultClient "github.com/hashicorp/vault-client-go" "github.com/hashicorp/vault-client-go/schema" "github.com/stretchr/testify/assert" + testcontainervault "github.com/testcontainers/testcontainers-go/modules/vault" "github.com/tidwall/gjson" ) @@ -21,18 +22,29 @@ const ( var ( ctx = context.Background() - vault *vaultContainer + vault *testcontainervault.VaultContainer ) func TestMain(m *testing.M) { var err error + opts := []testcontainervault.ContainerOptions{ + // WithImageName { + testcontainervault.WithImageName("vault:1.13.0"), + // } + // WithToken { + testcontainervault.WithToken(token), + // } + // WithLogLevel { + testcontainervault.WithLogLevel(testcontainervault.Debug), + // } + // WithInitCommand { + testcontainervault.WithInitCommand("secrets enable transit", "write -f transit/keys/my-key"), + testcontainervault.WithInitCommand("kv put secret/test1 foo1=bar1"), + // } + } + // StartContainer { - vault, err = StartContainer(ctx, - WithLogLevel(Debug), - WithToken(token), - WithInitCommand("secrets enable transit", "write -f transit/keys/my-key"), - WithInitCommand("kv put secret/test1 foo1=bar1"), - WithInitCommand("kv put secret/test2 foo2=bar2 foo3=bar3")) + vault, err = testcontainervault.StartContainer(ctx, opts...) // } if err != nil { log.Fatal(err) @@ -48,7 +60,7 @@ func TestMain(m *testing.M) { os.Exit(c) } -func TestVaultFirstSecretPathWithCLI(t *testing.T) { +func TestVaultGetSecretPathWithCLI(t *testing.T) { exec, reader, err := vault.Exec(ctx, []string{"vault", "kv", "get", "-format=json", "secret/test1"}) assert.Nil(t, err) assert.Equal(t, 0, exec) @@ -59,19 +71,7 @@ func TestVaultFirstSecretPathWithCLI(t *testing.T) { assert.Equal(t, "bar1", gjson.Get(string(bytes), "data.data.foo1").String()) } -func TestVaultSecondSecretPathWithCLI(t *testing.T) { - exec, reader, err := vault.Exec(ctx, []string{"vault", "kv", "get", "-format=json", "secret/test2"}) - assert.Nil(t, err) - assert.Equal(t, 0, exec) - - bytes, err := io.ReadAll(reader) - assert.Nil(t, err) - - assert.Equal(t, "bar2", gjson.Get(string(bytes), "data.data.foo2").String()) - assert.Equal(t, "bar3", gjson.Get(string(bytes), "data.data.foo3").String()) -} - -func TestVaultFirstSecretPathWithHTTP(t *testing.T) { +func TestVaultGetSecretPathWithHTTP(t *testing.T) { hostAddress, err := vault.HttpHostAddress(ctx) assert.Nil(t, err) @@ -88,25 +88,7 @@ func TestVaultFirstSecretPathWithHTTP(t *testing.T) { assert.Equal(t, "bar1", gjson.Get(string(body), "data.data.foo1").String()) } -func TestVaultSecondSecretPathWithHTTP(t *testing.T) { - hostAddress, err := vault.HttpHostAddress(ctx) - assert.Nil(t, err) - - request, _ := http.NewRequest(http.MethodGet, hostAddress+"/v1/secret/data/test2", nil) - request.Header.Add("X-Vault-Token", token) - - response, err := http.DefaultClient.Do(request) - assert.Nil(t, err) - defer response.Body.Close() - - body, err := io.ReadAll(response.Body) - assert.Nil(t, err) - - assert.Equal(t, "bar2", gjson.Get(string(body), "data.data.foo2").String()) - assert.Equal(t, "bar3", gjson.Get(string(body), "data.data.foo3").String()) -} - -func TestVaultFirstSecretPathWithClient(t *testing.T) { +func TestVaultGetSecretPathWithClient(t *testing.T) { hostAddress, _ := vault.HttpHostAddress(ctx) client, err := vaultClient.New( vaultClient.WithAddress(hostAddress), @@ -122,23 +104,6 @@ func TestVaultFirstSecretPathWithClient(t *testing.T) { assert.Equal(t, "bar1", s.Data["data"].(map[string]interface{})["foo1"]) } -func TestVaultSecondSecretPathWithClient(t *testing.T) { - hostAddress, _ := vault.HttpHostAddress(ctx) - client, err := vaultClient.New( - vaultClient.WithAddress(hostAddress), - vaultClient.WithRequestTimeout(30*time.Second), - ) - assert.Nil(t, err) - - err = client.SetToken(token) - assert.Nil(t, err) - - s, err := client.Secrets.KVv2Read(ctx, "test2") - assert.Nil(t, err) - assert.Equal(t, "bar2", s.Data["data"].(map[string]interface{})["foo2"]) - assert.Equal(t, "bar3", s.Data["data"].(map[string]interface{})["foo3"]) -} - func TestVaultWriteSecretWithClient(t *testing.T) { hostAddress, _ := vault.HttpHostAddress(ctx) client, err := vaultClient.New( From f6d5f5e7c4752322c807edc140ee4d293cebbd83 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 23 Mar 2023 17:39:56 +0300 Subject: [PATCH 38/40] remove log level option --- modules/vault/log_level.go | 14 -------------- modules/vault/vault.go | 7 ------- modules/vault/vault_test.go | 3 --- 3 files changed, 24 deletions(-) delete mode 100644 modules/vault/log_level.go diff --git a/modules/vault/log_level.go b/modules/vault/log_level.go deleted file mode 100644 index ac322feb77..0000000000 --- a/modules/vault/log_level.go +++ /dev/null @@ -1,14 +0,0 @@ -package vault - -// LogLevel is a custom type that represents a logging level for the Vault -type LogLevel string - -// The following constants define the possible logging levels for the Vault -// The default log level is info -const ( - Trace LogLevel = "trace" - Debug LogLevel = "debug" - Info LogLevel = "info" - Warn LogLevel = "warn" - Error LogLevel = "err" -) diff --git a/modules/vault/vault.go b/modules/vault/vault.go index 9d281d6b3f..6913365804 100644 --- a/modules/vault/vault.go +++ b/modules/vault/vault.go @@ -67,13 +67,6 @@ func WithToken(token string) ContainerOptions { } } -// WithLogLevel is an option function that sets the logging level for the Vault -func WithLogLevel(logLevel LogLevel) ContainerOptions { - return func(req *testcontainers.ContainerRequest) { - req.Env["VAULT_LOG_LEVEL"] = string(logLevel) - } -} - // WithInitCommand is an option function that adds a set of initialization commands to the Vault's configuration func WithInitCommand(commands ...string) ContainerOptions { return func(req *testcontainers.ContainerRequest) { diff --git a/modules/vault/vault_test.go b/modules/vault/vault_test.go index 4d2551f35f..23efd0a86d 100644 --- a/modules/vault/vault_test.go +++ b/modules/vault/vault_test.go @@ -34,9 +34,6 @@ func TestMain(m *testing.M) { // WithToken { testcontainervault.WithToken(token), // } - // WithLogLevel { - testcontainervault.WithLogLevel(testcontainervault.Debug), - // } // WithInitCommand { testcontainervault.WithInitCommand("secrets enable transit", "write -f transit/keys/my-key"), testcontainervault.WithInitCommand("kv put secret/test1 foo1=bar1"), From fcfa0cba89502b2577f0b6c98100261d22a8ebb0 Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 23 Mar 2023 17:42:22 +0300 Subject: [PATCH 39/40] update default image --- modules/vault/vault.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault/vault.go b/modules/vault/vault.go index 6913365804..76d64dd8a2 100644 --- a/modules/vault/vault.go +++ b/modules/vault/vault.go @@ -12,7 +12,7 @@ import ( const ( defaultPort = "8200" - defaultImageName = "vault:1.13.0" + defaultImageName = "hashicorp/vault:1.13.0" ) // ContainerOptions is a function that can be used to configure the Vault container From e845378045ed7d5fcc468fdcef3a878afd4ff8df Mon Sep 17 00:00:00 2001 From: "alihan.yalcin" Date: Thu, 23 Mar 2023 17:53:39 +0300 Subject: [PATCH 40/40] update docs --- docs/modules/vault.md | 16 +++++++++------- modules/vault/vault_test.go | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/modules/vault.md b/docs/modules/vault.md index 372da297a3..aef8362c88 100644 --- a/docs/modules/vault.md +++ b/docs/modules/vault.md @@ -30,6 +30,10 @@ It takes a context and zero or more Option values to configure the container. ### Use client library to read data from Vault container: +Add Vault Client module to your Go dependencies: +``` +go get -u github.com/hashicorp/vault-client-go +``` [Use library to read data](../../modules/vault/vault_test.go) inside_block:TestVaultGetSecretPathWithClient @@ -39,7 +43,11 @@ It takes a context and zero or more Option values to configure the container. You can set below options to create Vault container. ### Image -If you need to set a different Vault image, you can use the `WithImageName`. Default image name is `vault:1.13.0` +If you need to set a different Vault image, you can use the `WithImageName`. + +!!!info + Default image name is `hashicorp/vault:1.13.0`. + [Set image name](../../modules/vault/vault_test.go) inside_block:WithImageName @@ -50,12 +58,6 @@ If you need to add token authentication, you can use the `WithToken`. [Add token authentication](../../modules/vault/vault_test.go) inside_block:WithToken -### Log Level -If you need to change log level, you can use the `WithLogLevel`. Default log level is `info` - -[Change log level](../../modules/vault/vault_test.go) inside_block:WithLogLevel - - ### Command If you need to run vault command in the container, you can use the `WithInitCommand`. diff --git a/modules/vault/vault_test.go b/modules/vault/vault_test.go index 23efd0a86d..18f6213b60 100644 --- a/modules/vault/vault_test.go +++ b/modules/vault/vault_test.go @@ -29,7 +29,7 @@ func TestMain(m *testing.M) { var err error opts := []testcontainervault.ContainerOptions{ // WithImageName { - testcontainervault.WithImageName("vault:1.13.0"), + testcontainervault.WithImageName("hashicorp/vault:1.13.0"), // } // WithToken { testcontainervault.WithToken(token),