From 2ad5745d58b353b0500cc07e96f0c176c9be6c69 Mon Sep 17 00:00:00 2001 From: Lctrs Date: Thu, 12 Jan 2023 21:17:22 +0100 Subject: [PATCH] feat: migrate from libcompose to compose-go (#1547) * feat: migrate from libcompose to compose-go libcompose has been deprecated since summer 2021 in favor of https://github.com/compose-spec/compose-go. Kompose should now be able to load all versions of compose. * chore: replace golint with staticcheck golint has been deprecated. Recommended replacement is staticcheck. --- .github/workflows/go.yml | 11 +- .github/workflows/golangci-lint.yml | 21 - .github/workflows/lint.yml | 26 + .github/workflows/test.yml | 16 +- .golangci.yml | 2 +- Makefile | 10 +- cmd/completion.go | 8 +- docs/conversion.md | 22 +- go.mod | 13 +- go.sum | 88 +- pkg/kobject/kobject.go | 111 +- pkg/loader/compose/compose.go | 788 ++++++++++++- pkg/loader/compose/compose_test.go | 178 ++- pkg/loader/compose/v1v2.go | 417 ------- pkg/loader/compose/v3.go | 1009 ----------------- pkg/transformer/kubernetes/k8sutils.go | 8 +- pkg/transformer/kubernetes/k8sutils_test.go | 24 +- pkg/transformer/kubernetes/kubernetes.go | 23 +- pkg/transformer/kubernetes/kubernetes_test.go | 16 +- pkg/transformer/openshift/openshift.go | 4 +- pkg/transformer/openshift/openshift_test.go | 6 +- pkg/transformer/utils.go | 2 +- pkg/transformer/utils_test.go | 6 +- pkg/utils/docker/push.go | 7 +- script/test/cmd/tests_new.sh | 6 +- .../output-k8s-empty-vols-template.yaml | 19 + .../fixtures/change-in-volume/output-k8s.yaml | 18 + .../output-os-empty-vols-template.yaml | 2 + .../fixtures/change-in-volume/output-os.yaml | 2 + .../output-k8s-withlabel.yaml | 18 + .../fixtures/configmap-volume/output-k8s.yaml | 18 + .../configmap-volume/output-os-withlabel.yaml | 2 + .../fixtures/configmap-volume/output-os.yaml | 2 + .../placement/output-placement-k8s.yaml | 17 + .../deploy/placement/output-placement-os.yaml | 1 + .../envvars-interpolation/output-k8s.yaml | 17 + .../envvars-interpolation/output-os.yaml | 1 + script/test/fixtures/expose/output-k8s.yaml | 19 + script/test/fixtures/expose/output-os.yaml | 2 + .../healthcheck/output-healthcheck-k8s.yaml | 123 +- .../healthcheck/output-healthcheck-os.yaml | 4 + .../fixtures/multiple-files/output-k8s.yaml | 19 + .../fixtures/multiple-files/output-os.yaml | 2 + .../multiple-type-volumes/output-k8s.yaml | 18 + .../multiple-type-volumes/output-os.yaml | 2 + .../fixtures/redis-example/docker-compose.yml | 21 +- .../fixtures/service-group/output-k8s.yaml | 17 + .../single-file-output/output-k8s.yaml | 18 + .../test/fixtures/statefulset/output-k8s.yaml | 18 + .../test/fixtures/statefulset/output-os.yaml | 4 + script/test/fixtures/v2/output-k8s.yaml | 18 + script/test/fixtures/v2/output-os.yaml | 2 + script/test/fixtures/v3.0/output-k8s.yaml | 25 +- script/test/fixtures/v3.0/output-os.yaml | 3 +- .../volume-mounts/windows/output-k8s.yaml | 17 + .../volume-mounts/windows/output-os.yaml | 1 + script/test_in_container/Dockerfile | 2 +- 57 files changed, 1407 insertions(+), 1867 deletions(-) delete mode 100644 .github/workflows/golangci-lint.yml create mode 100644 .github/workflows/lint.yml delete mode 100644 pkg/loader/compose/v1v2.go delete mode 100644 pkg/loader/compose/v3.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 9e6894c8..798d80fc 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -17,19 +17,20 @@ jobs: steps: - name: Set up Go 1.x - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: - go-version: ^1.16 + go-version: ^1.19 id: go - name: Check out code into the Go module directory - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Build run: make bin - name: Upload a Build Artifact - uses: actions/upload-artifact@v2.1.4 - with: + uses: actions/upload-artifact@v3 + with: + name: "kompose" path: "kompose" diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml deleted file mode 100644 index 390a52d4..00000000 --- a/.github/workflows/golangci-lint.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: golangci-lint -on: - pull_request: -jobs: - golangci: - strategy: - matrix: - go: [1.16, 1.17] - name: lint - runs-on: ubuntu-latest - steps: - - uses: actions/setup-go@v3 - with: - go-version: ${{ matrix.go }} - - uses: actions/checkout@v2 - - name: golangci-lint - uses: golangci/golangci-lint-action@v3 - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.29 - args: --timeout 5m diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..12ec71ae --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,26 @@ +name: lint +on: + pull_request: +jobs: + lint: + strategy: + matrix: + go: [1.18, 1.19] + name: lint + runs-on: ubuntu-latest + steps: + - name: "Checkout" + uses: actions/checkout@v3 + - name: "Install golang" + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.go }} + - name: "Run go vet" + run: "go vet ./pkg/..." + - name: "Run staticcheck" + uses: dominikh/staticcheck-action@v1 + with: + cache-key: "${{ matrix.go }}" + install-go: false + version: "latest" + working-directory: "pkg" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f26a17f7..65512bfb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,14 +10,14 @@ env: jobs: test: name: Test with ${{ matrix.go }} and CROSS_COMPILE=${{ matrix.cross_compile }} - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest strategy: matrix: - go: [1.16, 1.17] + go: [1.18, 1.19] cross_compile: [true, false] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 with: go-version: ${{ matrix.go }} - name: Run tests @@ -27,13 +27,13 @@ jobs: run: make cross docs: name: Build docs and Coveralls integration - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest needs: test steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 with: - go-version: 1.16 + go-version: 1.19 - name: Create .coverprofile for each targeted directory by re:running tests run: make test - name: Collect all .coverprofile files and save it to one file gover.coverprofile diff --git a/.golangci.yml b/.golangci.yml index c910f13c..acf73136 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -12,7 +12,7 @@ linters: # - errcheck # - goconst - goimports -# - golint +# - staticcheck - goprintffuncname # - gosimple - govet diff --git a/Makefile b/Makefile index 33b905ed..d5a70e0e 100644 --- a/Makefile +++ b/Makefile @@ -91,15 +91,15 @@ gen-cmd: # run all validation tests .PHONY: validate -validate: gofmt vet lint +validate: gofmt vet staticcheck .PHONY: vet vet: go vet ./pkg/... -.PHONY: lint -lint: - golint ./pkg/... +.PHONY: staticcheck +staticcheck: + staticcheck ./pkg/... .PHONY: gofmt gofmt: @@ -114,7 +114,7 @@ test: bin test-dep validate test-unit-cover install test-cmd test-dep: go install github.com/mattn/goveralls@latest go install github.com/modocache/gover@latest - go install golang.org/x/lint/golint@latest + go install honnef.co/go/tools/cmd/staticcheck@latest go install github.com/mitchellh/gox@latest diff --git a/cmd/completion.go b/cmd/completion.go index 873d32be..ab34afa2 100644 --- a/cmd/completion.go +++ b/cmd/completion.go @@ -63,7 +63,7 @@ func init() { } /* - Fish shell auto-completion support +Fish shell auto-completion support */ func runCompletionFish(out io.Writer, kompose *cobra.Command) error { kompose.GenFishCompletion(out, true) @@ -79,9 +79,9 @@ complete -c kompose -n "__fish_seen_subcommand_from completion" -a "bash zsh fis } /* - This is copied from - https://github.com/kubernetes/kubernetes/blob/ea18d5c32ee7c320fe96dda6b0c757476908e696/pkg/kubectl/cmd/completion.go - in order to generate ZSH completion support. +This is copied from +https://github.com/kubernetes/kubernetes/blob/ea18d5c32ee7c320fe96dda6b0c757476908e696/pkg/kubectl/cmd/completion.go +in order to generate ZSH completion support. */ func runCompletionZsh(out io.Writer, kompose *cobra.Command) error { zshInitialization := ` diff --git a/docs/conversion.md b/docs/conversion.md index 79d19d4e..86e79b4d 100644 --- a/docs/conversion.md +++ b/docs/conversion.md @@ -14,26 +14,10 @@ redirect_from: This document outlines all possible conversion details regarding `docker-compose.yaml` values to Kubernetes / OpenShift artifacts. -## Version Table +## Version Support -| Supported | Compose Version | Docker Engine Version | -|------------|-----------------|-----------------------| -| N | 3.8 | 19.03.0+ | -| N | 3.7 | 18.06.0+ | -| N | 3.6 | 18.02.0+ | -| N | 3.5 | 17.12.0+ | -| N | 3.4 | 17.09.0+ | -| Y | 3.3 | 17.06.0+ | -| Y | 3.2 | 17.04.0+ | -| Y | 3.1 | 1.13.1+ | -| Y | 3.0 | 1.13.0+ | -| Y | 2.4 | 17.12.0+ | -| Y | 2.3 | 17.06.0+ | -| Y | 2.2 | 1.13.0+ | -| Y | 2.1 | 1.12.0+ | -| Y | 2.0 | 1.10.0+ | - -**Note:** We don't support anything 3.4 and above at the moment. It is reccomended to specify `version: "3.3"` in your `docker-compose.yaml` and converting. We use a library called [libcompose](https://github.com/docker/libcompose) that supports up to version `3.3`. If you are interested in adding additional support, please open up a PR! +Under the hood, we're using [compose-go](https://github.com/compose-spec/compose-go), the reference library for parsing Compose files. We should be able to load all versions of Compose files. +We're doing our best to keep it up to date as soon as possible in our releases to be compatible with the latest features defined in the [Compose specification](https://github.com/compose-spec/compose-spec/blob/master/spec.md). If you absolutely need a feature we don't support yet, please open a PR! ## Conversion Table diff --git a/go.mod b/go.mod index 6aec079a..5fd9ba9a 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,6 @@ go 1.13 replace github.com/Sirupsen/logrus => github.com/sirupsen/logrus v1.8.1 -replace github.com/docker/libcompose => github.com/docker/libcompose v0.4.1-0.20190808084053-143e0f3f1ab9 - replace github.com/docker/cli => github.com/docker/cli v20.10.16+incompatible replace github.com/xeipuuv/gojsonschema => github.com/xeipuuv/gojsonschema v1.2.1-0.20201027075954-b076d39a02e5 @@ -31,28 +29,25 @@ replace github.com/emicklei/go-restful => github.com/emicklei/go-restful v2.16.0 replace golang.org/x/crypto => golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d require ( + github.com/compose-spec/compose-go v1.8.2 github.com/containerd/containerd v1.6.4 // indirect github.com/deckarep/golang-set v1.7.1 - github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 - github.com/docker/go-connections v0.4.0 - github.com/docker/libcompose v0.4.0 github.com/fatih/structs v1.1.0 github.com/fsouza/go-dockerclient v1.6.6 - github.com/google/go-cmp v0.5.8 + github.com/google/go-cmp v0.5.9 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/joho/godotenv v1.3.0 github.com/novln/docker-parser v1.0.0 github.com/openshift/api v0.0.0-20200803131051-87466835fcc0 github.com/pkg/errors v0.9.1 - github.com/sirupsen/logrus v1.8.1 + github.com/sirupsen/logrus v1.9.0 github.com/spf13/cast v1.3.1 github.com/spf13/cobra v1.1.3 github.com/spf13/viper v1.7.1 - golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect golang.org/x/text v0.3.8 // indirect golang.org/x/tools v0.1.12 gopkg.in/yaml.v2 v2.4.0 - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b + gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.22.5 k8s.io/apimachinery v0.22.5 ) diff --git a/go.sum b/go.sum index 4b527e62..6f805080 100644 --- a/go.sum +++ b/go.sum @@ -35,27 +35,29 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= +github.com/Azure/azure-sdk-for-go v56.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= 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/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Microsoft/go-winio v0.3.8/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.15-0.20200113171025-3fe6c5262873/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= @@ -68,6 +70,7 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -80,14 +83,20 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.43.16/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -113,6 +122,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/compose-spec/compose-go v1.8.2 h1:sUQvDxnPgpcOyoxC/lz7mFTrTlHeZ6LWyuASYetkOqw= +github.com/compose-spec/compose-go v1.8.2/go.mod h1:Tb5Ae2PsYN3GTqYqzl2IRbTPiJtPZZjMw8UKUvmehFk= github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= @@ -174,24 +185,24 @@ 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/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/cli v20.10.16+incompatible h1:aLQ8XowgKpR3/IysPj8qZQJBVQ+Qws61icFuZl6iKYs= +github.com/distribution/distribution/v3 v3.0.0-20221103125252-ebfa2a0ac0a9 h1:doprs/RuXCuN864IfxC3h2qocrt158wGv3A5mcqSZQw= +github.com/distribution/distribution/v3 v3.0.0-20221103125252-ebfa2a0ac0a9/go.mod h1:6rIc5NMSjXjjnwzWWy3HAm9gDBu+X7aCzL8VrHIKgxM= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v20.10.16+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.0-beta1.0.20201030232932-c2cc352355d4+incompatible h1:7Wcl0zstnDmC7woif4M/PWN8kql0+m1h38WhF/raC4E= github.com/docker/docker v20.10.0-beta1.0.20201030232932-c2cc352355d4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= -github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 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-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/libcompose v0.4.1-0.20190808084053-143e0f3f1ab9 h1:Z+aRYtQXR6iFSAnoaAq/dUTcZvL1ph8uWlsrmfIP8Bs= -github.com/docker/libcompose v0.4.1-0.20190808084053-143e0f3f1ab9/go.mod h1:YZ/h8H7gZ7/SOoviPEvSYgHomvbB82iyHvGXLVTNFwQ= -github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +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/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -212,8 +223,6 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= @@ -263,6 +272,7 @@ github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 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/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -270,6 +280,8 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -303,6 +315,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= 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/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= @@ -318,8 +331,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -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/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -348,8 +361,7 @@ github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2c github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v0.0.0-20160317213430-0eeaf8392f5b/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -377,6 +389,7 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -387,11 +400,14 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= @@ -424,7 +440,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v0.0.0-20150511174710-5cf931ef8f76/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -442,6 +457,7 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -456,8 +472,10 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mount v0.1.0 h1:Ytx78EatgFKtrqZ0BvJ0UtJE472ZvawVmil6pIfuCCU= @@ -477,7 +495,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 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= @@ -486,6 +503,7 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/novln/docker-parser v1.0.0 h1:PjEBd9QnKixcWczNGyEdfUrP6GR0YUilAqG7Wksg3uc= @@ -512,12 +530,10 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 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 v0.0.0-20170515205857-f03dbe35d449/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= @@ -555,6 +571,7 @@ github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -566,6 +583,7 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -593,8 +611,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= 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/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -628,13 +647,18 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 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/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -644,7 +668,6 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1 github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= @@ -667,6 +690,9 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= @@ -796,6 +822,7 @@ golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 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= @@ -817,8 +844,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/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-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -899,6 +927,7 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 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.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -933,6 +962,7 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -974,7 +1004,6 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -1039,13 +1068,16 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/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 v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/kobject/kobject.go b/pkg/kobject/kobject.go index b595cd39..9237255c 100644 --- a/pkg/kobject/kobject.go +++ b/pkg/kobject/kobject.go @@ -21,8 +21,7 @@ import ( "strconv" "time" - dockerCliTypes "github.com/docker/cli/cli/compose/types" - "github.com/docker/libcompose/yaml" + "github.com/compose-spec/compose-go/types" deployapi "github.com/openshift/api/apps/v1" "github.com/pkg/errors" "github.com/spf13/cast" @@ -38,7 +37,7 @@ type KomposeObject struct { // as they can have different names. For example environment variables are called environment in compose but Env in bundle. LoadedFrom string - Secrets map[string]dockerCliTypes.SecretConfig + Secrets types.Secrets } // ConvertOptions holds all options that controls transformation process @@ -99,64 +98,64 @@ type ServiceConfigGroup []ServiceConfig type ServiceConfig struct { Name string ContainerName string - Image string `compose:"image"` - Environment []EnvVar `compose:"environment"` - EnvFile []string `compose:"env_file"` - Port []Ports `compose:"ports"` - Command []string `compose:"command"` - WorkingDir string `compose:""` - DomainName string `compose:"domainname"` - HostName string `compose:"hostname"` - Args []string `compose:"args"` - VolList []string `compose:"volumes"` - Network []string `compose:"network"` - Labels map[string]string `compose:"labels"` - Annotations map[string]string `compose:""` - CPUSet string `compose:"cpuset"` - CPUShares int64 `compose:"cpu_shares"` - CPUQuota int64 `compose:"cpu_quota"` - CPULimit int64 `compose:""` - CPUReservation int64 `compose:""` - CapAdd []string `compose:"cap_add"` - CapDrop []string `compose:"cap_drop"` - Expose []string `compose:"expose"` - ImagePullPolicy string `compose:"kompose.image-pull-policy"` - Pid string `compose:"pid"` - Privileged bool `compose:"privileged"` - Restart string `compose:"restart"` - User string `compose:"user"` - VolumesFrom []string `compose:"volumes_from"` - ServiceType string `compose:"kompose.service.type"` - NodePortPort int32 `compose:"kompose.service.nodeport.port"` - StopGracePeriod string `compose:"stop_grace_period"` - Build string `compose:"build"` - BuildArgs map[string]*string `compose:"build-args"` - ExposeService string `compose:"kompose.service.expose"` - ExposeServicePath string `compose:"kompose.service.expose.path"` - BuildLabels map[string]string `compose:"build-labels"` - ExposeServiceTLS string `compose:"kompose.service.expose.tls-secret"` - ExposeServiceIngressClassName string `compose:"kompose.service.expose.ingress-class-name"` - ImagePullSecret string `compose:"kompose.image-pull-secret"` - Stdin bool `compose:"stdin_open"` - Tty bool `compose:"tty"` - MemLimit yaml.MemStringorInt `compose:"mem_limit"` - MemReservation yaml.MemStringorInt `compose:""` - DeployMode string `compose:""` + Image string `compose:"image"` + Environment []EnvVar `compose:"environment"` + EnvFile []string `compose:"env_file"` + Port []Ports `compose:"ports"` + Command []string `compose:"command"` + WorkingDir string `compose:""` + DomainName string `compose:"domainname"` + HostName string `compose:"hostname"` + Args []string `compose:"args"` + VolList []string `compose:"volumes"` + Network []string `compose:"network"` + Labels map[string]string `compose:"labels"` + Annotations map[string]string `compose:""` + CPUSet string `compose:"cpuset"` + CPUShares int64 `compose:"cpu_shares"` + CPUQuota int64 `compose:"cpu_quota"` + CPULimit int64 `compose:""` + CPUReservation int64 `compose:""` + CapAdd []string `compose:"cap_add"` + CapDrop []string `compose:"cap_drop"` + Expose []string `compose:"expose"` + ImagePullPolicy string `compose:"kompose.image-pull-policy"` + Pid string `compose:"pid"` + Privileged bool `compose:"privileged"` + Restart string `compose:"restart"` + User string `compose:"user"` + VolumesFrom []string `compose:"volumes_from"` + ServiceType string `compose:"kompose.service.type"` + NodePortPort int32 `compose:"kompose.service.nodeport.port"` + StopGracePeriod string `compose:"stop_grace_period"` + Build string `compose:"build"` + BuildArgs map[string]*string `compose:"build-args"` + ExposeService string `compose:"kompose.service.expose"` + ExposeServicePath string `compose:"kompose.service.expose.path"` + BuildLabels map[string]string `compose:"build-labels"` + ExposeServiceTLS string `compose:"kompose.service.expose.tls-secret"` + ExposeServiceIngressClassName string `compose:"kompose.service.expose.ingress-class-name"` + ImagePullSecret string `compose:"kompose.image-pull-secret"` + Stdin bool `compose:"stdin_open"` + Tty bool `compose:"tty"` + MemLimit types.UnitBytes `compose:"mem_limit"` + MemReservation types.UnitBytes `compose:""` + DeployMode string `compose:""` // DeployLabels mapping to kubernetes labels - DeployLabels map[string]string `compose:""` - DeployUpdateConfig dockerCliTypes.UpdateConfig `compose:""` - TmpFs []string `compose:"tmpfs"` - Dockerfile string `compose:"dockerfile"` - Replicas int `compose:"replicas"` - GroupAdd []int64 `compose:"group_add"` - Volumes []Volumes `compose:""` - Secrets []dockerCliTypes.ServiceSecretConfig + DeployLabels map[string]string `compose:""` + DeployUpdateConfig types.UpdateConfig `compose:""` + TmpFs []string `compose:"tmpfs"` + Dockerfile string `compose:"dockerfile"` + Replicas int `compose:"replicas"` + GroupAdd []int64 `compose:"group_add"` + Volumes []Volumes `compose:""` + Secrets []types.ServiceSecretConfig HealthChecks HealthChecks `compose:""` Placement Placement `compose:""` //This is for long LONG SYNTAX link(https://docs.docker.com/compose/compose-file/#long-syntax) - Configs []dockerCliTypes.ServiceConfigObjConfig `compose:""` + Configs []types.ServiceConfigObjConfig `compose:""` //This is for SHORT SYNTAX link(https://docs.docker.com/compose/compose-file/#configs) - ConfigsMetaData map[string]dockerCliTypes.ConfigObjConfig `compose:""` + ConfigsMetaData types.Configs `compose:""` WithKomposeAnnotation bool `compose:""` InGroup bool diff --git a/pkg/loader/compose/compose.go b/pkg/loader/compose/compose.go index da0bceb2..fec0c01f 100644 --- a/pkg/loader/compose/compose.go +++ b/pkg/loader/compose/compose.go @@ -18,30 +18,36 @@ package compose import ( "fmt" + "os" "reflect" + "strconv" "strings" + "time" - "gopkg.in/yaml.v2" - - "github.com/docker/libcompose/project" + "github.com/compose-spec/compose-go/cli" + "github.com/compose-spec/compose-go/types" "github.com/fatih/structs" + "github.com/google/shlex" "github.com/kubernetes/kompose/pkg/kobject" + "github.com/kubernetes/kompose/pkg/transformer" "github.com/pkg/errors" log "github.com/sirupsen/logrus" + "github.com/spf13/cast" + api "k8s.io/api/core/v1" ) -//StdinData is data bytes read from stdin +// StdinData is data bytes read from stdin var StdinData []byte // Compose is docker compose file loader, implements Loader interface type Compose struct { } -// checkUnsupportedKey checks if libcompose project contains +// checkUnsupportedKey checks if compose-go project contains // keys that are not supported by this loader. // list of all unsupported keys are stored in unsupportedKey variable // returns list of unsupported YAML keys from docker-compose -func checkUnsupportedKey(composeProject *project.Project) []string { +func checkUnsupportedKey(composeProject *types.Project) []string { // list of all unsupported keys for this loader // this is map to make searching for keys easier // to make sure that unsupported key is not going to be reported twice @@ -79,18 +85,18 @@ func checkUnsupportedKey(composeProject *project.Project) []string { // Root level keys are not yet supported except Network // Check to see if the default network is available and length is only equal to one. - if _, ok := composeProject.NetworkConfigs["default"]; ok && len(composeProject.NetworkConfigs) == 1 { + if _, ok := composeProject.Networks["default"]; ok && len(composeProject.Networks) == 1 { log.Debug("Default network found") } // Root level volumes are not yet supported - if len(composeProject.VolumeConfigs) > 0 { + if len(composeProject.Volumes) > 0 { keysFound = append(keysFound, "root level volumes") } - for _, serviceConfig := range composeProject.ServiceConfigs.All() { + for _, serviceConfig := range composeProject.AllServices() { // this reflection is used in check for empty arrays - val := reflect.ValueOf(serviceConfig).Elem() + val := reflect.ValueOf(serviceConfig) s := structs.New(serviceConfig) for _, f := range s.Fields() { @@ -109,7 +115,7 @@ func checkUnsupportedKey(composeProject *project.Project) []string { yamlTagName := strings.Split(f.Tag("yaml"), ",")[0] if f.Name() == "Networks" { // networks always contains one default element, even it isn't declared in compose v2. - if len(serviceConfig.Networks.Networks) == 1 && serviceConfig.Networks.Networks[0].Name == "default" { + if len(serviceConfig.Networks) == 1 && serviceConfig.NetworksByPriority()[0] == "default" { // this is empty Network definition, skip it continue } @@ -144,61 +150,733 @@ func checkUnsupportedKey(composeProject *project.Project) []string { // LoadFile loads a compose file into KomposeObject func (c *Compose) LoadFile(files []string) (kobject.KomposeObject, error) { - // Load the json / yaml file in order to get the version value - var version string - - for _, file := range files { - composeVersion, err := getVersionFromFile(file) - if err != nil { - return kobject.KomposeObject{}, errors.Wrap(err, "Unable to load yaml/json file for version parsing") - } - - // Check that the previous file loaded matches. - if len(files) > 0 && version != "" && version != composeVersion { - return kobject.KomposeObject{}, errors.New("All Docker Compose files must be of the same version") - } - version = composeVersion + // Gather the working directory + workingDir, err := getComposeFileDir(files) + if err != nil { + return kobject.KomposeObject{}, err } - log.Debugf("Docker Compose version: %s", version) + projectOptions, err := cli.NewProjectOptions(files, cli.WithOsEnv, cli.WithWorkingDirectory(workingDir), cli.WithInterpolation(false)) + if err != nil { + return kobject.KomposeObject{}, errors.Wrap(err, "Unable to create compose options") + } - // Convert based on version - switch version { - // Use libcompose for 1 or 2 - // If blank, it's assumed it's 1 or 2 - case "", "1", "1.0", "2", "2.0", "2.1", "2.2": - komposeObject, err := parseV1V2(files) - if err != nil { - return kobject.KomposeObject{}, err + project, err := cli.ProjectFromOptions(projectOptions) + if err != nil { + return kobject.KomposeObject{}, errors.Wrap(err, "Unable to load files") + } + + komposeObject, err := dockerComposeToKomposeMapping(project) + if err != nil { + return kobject.KomposeObject{}, err + } + return komposeObject, nil +} + +func loadPlacement(placement types.Placement) kobject.Placement { + komposePlacement := kobject.Placement{ + PositiveConstraints: make(map[string]string), + NegativeConstraints: make(map[string]string), + Preferences: make([]string, 0, len(placement.Preferences)), + } + + // Convert constraints + equal, notEqual := " == ", " != " + for _, j := range placement.Constraints { + operator := equal + if strings.Contains(j, notEqual) { + operator = notEqual } - return komposeObject, nil - // Use docker/cli for 3 - case "3", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8": - komposeObject, err := parseV3(files) - if err != nil { - return kobject.KomposeObject{}, err + p := strings.Split(j, operator) + if len(p) < 2 { + log.Warnf("Failed to parse placement constraints %s, the correct format is 'label == xxx'", j) + continue } - return komposeObject, nil + + key, err := convertDockerLabel(p[0]) + if err != nil { + log.Warn("Ignore placement constraints: ", err.Error()) + continue + } + + if operator == equal { + komposePlacement.PositiveConstraints[key] = p[1] + } else if operator == notEqual { + komposePlacement.NegativeConstraints[key] = p[1] + } + } + + // Convert preferences + for _, p := range placement.Preferences { + // Spread is the only supported strategy currently + label, err := convertDockerLabel(p.Spread) + if err != nil { + log.Warn("Ignore placement preferences: ", err.Error()) + continue + } + komposePlacement.Preferences = append(komposePlacement.Preferences, label) + } + return komposePlacement +} + +// Convert docker label to k8s label +func convertDockerLabel(dockerLabel string) (string, error) { + switch dockerLabel { + case "node.hostname": + return "kubernetes.io/hostname", nil + case "engine.labels.operatingsystem": + return "kubernetes.io/os", nil default: - return kobject.KomposeObject{}, fmt.Errorf("version %s of Docker Compose is not supported. Please use version 1, 2 or 3", version) + if strings.HasPrefix(dockerLabel, "node.labels.") { + return strings.TrimPrefix(dockerLabel, "node.labels."), nil + } + } + errMsg := fmt.Sprint(dockerLabel, " is not supported, only 'node.hostname', 'engine.labels.operatingsystem' and 'node.labels.xxx' (ex: node.labels.something == anything) is supported") + return "", errors.New(errMsg) +} + +// Convert the Docker Compose volumes to []string (the old way) +// TODO: Check to see if it's a "bind" or "volume". Ignore for now. +// TODO: Refactor it similar to loadPorts +// See: https://docs.docker.com/compose/compose-file/#long-syntax-3 +func loadVolumes(volumes []types.ServiceVolumeConfig) []string { + var volArray []string + for _, vol := range volumes { + // There will *always* be Source when parsing + v := vol.Source + + if vol.Target != "" { + v = v + ":" + vol.Target + } + + if vol.ReadOnly { + v = v + ":ro" + } + + volArray = append(volArray, v) + } + return volArray +} + +// Convert Docker Compose ports to kobject.Ports +// expose ports will be treated as TCP ports +func loadPorts(ports []types.ServicePortConfig, expose []string) []kobject.Ports { + komposePorts := []kobject.Ports{} + exist := map[string]bool{} + + for _, port := range ports { + // Convert to a kobject struct with ports + komposePorts = append(komposePorts, kobject.Ports{ + HostPort: cast.ToInt32(port.Published), + ContainerPort: int32(port.Target), + HostIP: port.HostIP, + Protocol: strings.ToUpper(port.Protocol), + }) + exist[cast.ToString(port.Target)+port.Protocol] = true + } + + for _, port := range expose { + portValue := port + protocol := string(api.ProtocolTCP) + if strings.Contains(portValue, "/") { + splits := strings.Split(port, "/") + portValue = splits[0] + protocol = splits[1] + } + + if exist[portValue+protocol] { + continue + } + komposePorts = append(komposePorts, kobject.Ports{ + HostPort: cast.ToInt32(portValue), + ContainerPort: cast.ToInt32(portValue), + HostIP: "", + Protocol: strings.ToUpper(protocol), + }) + } + + return komposePorts +} + +/* + Convert the HealthCheckConfig as designed by Docker to + +a Kubernetes-compatible format. +*/ +func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error) { + var test []string + var httpPath string + var httpPort, tcpPort, timeout, interval, retries, startPeriod int32 + var disable bool + + for key, value := range labels { + switch key { + case HealthCheckReadinessDisable: + disable = cast.ToBool(value) + case HealthCheckReadinessTest: + if len(value) > 0 { + test, _ = shlex.Split(value) + } + case HealthCheckReadinessHTTPGetPath: + httpPath = value + case HealthCheckReadinessHTTPGetPort: + httpPort = cast.ToInt32(value) + case HealthCheckReadinessTCPPort: + tcpPort = cast.ToInt32(value) + case HealthCheckReadinessInterval: + parse, err := time.ParseDuration(value) + if err != nil { + return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check interval variable") + } + interval = int32(parse.Seconds()) + case HealthCheckReadinessTimeout: + parse, err := time.ParseDuration(value) + if err != nil { + return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check timeout variable") + } + timeout = int32(parse.Seconds()) + case HealthCheckReadinessRetries: + retries = cast.ToInt32(value) + case HealthCheckReadinessStartPeriod: + parse, err := time.ParseDuration(value) + if err != nil { + return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check startPeriod variable") + } + startPeriod = int32(parse.Seconds()) + } + } + + if len(test) > 0 { + if test[0] == "NONE" { + disable = true + test = test[1:] + } + // Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test + if test[0] == "CMD" || test[0] == "CMD-SHELL" { + test = test[1:] + } + } + + return kobject.HealthCheck{ + Test: test, + HTTPPath: httpPath, + HTTPPort: httpPort, + TCPPort: tcpPort, + Timeout: timeout, + Interval: interval, + Retries: retries, + StartPeriod: startPeriod, + Disable: disable, + }, nil +} + +/* + Convert the HealthCheckConfig as designed by Docker to + +a Kubernetes-compatible format. +*/ +func parseHealthCheck(composeHealthCheck types.HealthCheckConfig, labels types.Labels) (kobject.HealthCheck, error) { + var httpPort, tcpPort, timeout, interval, retries, startPeriod int32 + var test []string + var httpPath string + + // Here we convert the timeout from 1h30s (example) to 36030 seconds. + if composeHealthCheck.Timeout != nil { + parse, err := time.ParseDuration(composeHealthCheck.Timeout.String()) + if err != nil { + return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check timeout variable") + } + timeout = int32(parse.Seconds()) + } + + if composeHealthCheck.Interval != nil { + parse, err := time.ParseDuration(composeHealthCheck.Interval.String()) + if err != nil { + return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check interval variable") + } + interval = int32(parse.Seconds()) + } + + if composeHealthCheck.Retries != nil { + retries = int32(*composeHealthCheck.Retries) + } + + if composeHealthCheck.StartPeriod != nil { + parse, err := time.ParseDuration(composeHealthCheck.StartPeriod.String()) + if err != nil { + return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check startPeriod variable") + } + startPeriod = int32(parse.Seconds()) + } + + if composeHealthCheck.Test != nil { + test = composeHealthCheck.Test[1:] + } + + for key, value := range labels { + switch key { + case HealthCheckLivenessHTTPGetPath: + httpPath = value + case HealthCheckLivenessHTTPGetPort: + httpPort = cast.ToInt32(value) + case HealthCheckLivenessTCPPort: + tcpPort = cast.ToInt32(value) + } + } + + // Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test + return kobject.HealthCheck{ + Test: test, + TCPPort: tcpPort, + HTTPPath: httpPath, + HTTPPort: httpPort, + Timeout: timeout, + Interval: interval, + Retries: retries, + StartPeriod: startPeriod, + }, nil +} + +func dockerComposeToKomposeMapping(composeObject *types.Project) (kobject.KomposeObject, error) { + // Step 1. Initialize what's going to be returned + komposeObject := kobject.KomposeObject{ + ServiceConfigs: make(map[string]kobject.ServiceConfig), + LoadedFrom: "compose", + Secrets: composeObject.Secrets, + } + + // Step 2. Parse through the object and convert it to kobject.KomposeObject! + // Here we "clean up" the service configuration so we return something that includes + // all relevant information as well as avoid the unsupported keys as well. + for _, composeServiceConfig := range composeObject.Services { + // Standard import + // No need to modify before importation + name := composeServiceConfig.Name + serviceConfig := kobject.ServiceConfig{} + serviceConfig.Name = name + serviceConfig.Image = composeServiceConfig.Image + serviceConfig.WorkingDir = composeServiceConfig.WorkingDir + serviceConfig.Annotations = composeServiceConfig.Labels + serviceConfig.CapAdd = composeServiceConfig.CapAdd + serviceConfig.CapDrop = composeServiceConfig.CapDrop + serviceConfig.Expose = composeServiceConfig.Expose + serviceConfig.Privileged = composeServiceConfig.Privileged + serviceConfig.User = composeServiceConfig.User + serviceConfig.Stdin = composeServiceConfig.StdinOpen + serviceConfig.Tty = composeServiceConfig.Tty + serviceConfig.TmpFs = composeServiceConfig.Tmpfs + serviceConfig.ContainerName = normalizeContainerNames(composeServiceConfig.ContainerName) + serviceConfig.Command = composeServiceConfig.Entrypoint + serviceConfig.Args = composeServiceConfig.Command + serviceConfig.Labels = composeServiceConfig.Labels + serviceConfig.HostName = composeServiceConfig.Hostname + serviceConfig.DomainName = composeServiceConfig.DomainName + serviceConfig.Secrets = composeServiceConfig.Secrets + + if composeServiceConfig.StopGracePeriod != nil { + serviceConfig.StopGracePeriod = composeServiceConfig.StopGracePeriod.String() + } + + if err := parseNetwork(&composeServiceConfig, &serviceConfig, composeObject); err != nil { + return kobject.KomposeObject{}, err + } + + if err := parseResources(&composeServiceConfig, &serviceConfig); err != nil { + return kobject.KomposeObject{}, err + } + + serviceConfig.Restart = composeServiceConfig.Restart + + if composeServiceConfig.Deploy != nil { + // Deploy keys + // mode: + serviceConfig.DeployMode = composeServiceConfig.Deploy.Mode + // labels + serviceConfig.DeployLabels = composeServiceConfig.Deploy.Labels + + // restart-policy: deploy.restart_policy.condition will rewrite restart option + // see: https://docs.docker.com/compose/compose-file/#restart_policy + if composeServiceConfig.Deploy.RestartPolicy != nil { + serviceConfig.Restart = composeServiceConfig.Deploy.RestartPolicy.Condition + } + + // replicas: + if composeServiceConfig.Deploy.Replicas != nil { + serviceConfig.Replicas = int(*composeServiceConfig.Deploy.Replicas) + } + + // placement: + serviceConfig.Placement = loadPlacement(composeServiceConfig.Deploy.Placement) + + if composeServiceConfig.Deploy.UpdateConfig != nil { + serviceConfig.DeployUpdateConfig = *composeServiceConfig.Deploy.UpdateConfig + } + + if composeServiceConfig.Deploy.EndpointMode == "vip" { + serviceConfig.ServiceType = string(api.ServiceTypeNodePort) + } + } + + // HealthCheck Liveness + if composeServiceConfig.HealthCheck != nil && !composeServiceConfig.HealthCheck.Disable { + var err error + serviceConfig.HealthChecks.Liveness, err = parseHealthCheck(*composeServiceConfig.HealthCheck, composeServiceConfig.Labels) + if err != nil { + return kobject.KomposeObject{}, errors.Wrap(err, "Unable to parse health check") + } + } + + // HealthCheck Readiness + var readiness, errReadiness = parseHealthCheckReadiness(composeServiceConfig.Labels) + if !readiness.Disable { + serviceConfig.HealthChecks.Readiness = readiness + if errReadiness != nil { + return kobject.KomposeObject{}, errors.Wrap(errReadiness, "Unable to parse health check") + } + } + + if serviceConfig.Restart == "unless-stopped" { + log.Warnf("Restart policy 'unless-stopped' in service %s is not supported, convert it to 'always'", name) + serviceConfig.Restart = "always" + } + + if composeServiceConfig.Build != nil { + serviceConfig.Build = composeServiceConfig.Build.Context + serviceConfig.Dockerfile = composeServiceConfig.Build.Dockerfile + serviceConfig.BuildArgs = composeServiceConfig.Build.Args + serviceConfig.BuildLabels = composeServiceConfig.Build.Labels + } + + // env + parseEnvironment(&composeServiceConfig, &serviceConfig) + + // Get env_file + serviceConfig.EnvFile = composeServiceConfig.EnvFile + + // Parse the ports + // v3 uses a new format called "long syntax" starting in 3.2 + // https://docs.docker.com/compose/compose-file/#ports + + // here we will translate `expose` too, they basically means the same thing in kubernetes + serviceConfig.Port = loadPorts(composeServiceConfig.Ports, serviceConfig.Expose) + + // Parse the volumes + // Again, in v3, we use the "long syntax" for volumes in terms of parsing + // https://docs.docker.com/compose/compose-file/#long-syntax-3 + serviceConfig.VolList = loadVolumes(composeServiceConfig.Volumes) + if err := parseKomposeLabels(composeServiceConfig.Labels, &serviceConfig); err != nil { + return kobject.KomposeObject{}, err + } + + // Log if the name will been changed + if normalizeServiceNames(name) != name { + log.Infof("Service name in docker-compose has been changed from %q to %q", name, normalizeServiceNames(name)) + } + + serviceConfig.Configs = composeServiceConfig.Configs + serviceConfig.ConfigsMetaData = composeObject.Configs + + // Get GroupAdd, group should be mentioned in gid format but not the group name + groupAdd, err := getGroupAdd(composeServiceConfig.GroupAdd) + if err != nil { + return kobject.KomposeObject{}, errors.Wrap(err, "GroupAdd should be mentioned in gid format, not a group name") + } + serviceConfig.GroupAdd = groupAdd + + // Final step, add to the array! + komposeObject.ServiceConfigs[normalizeServiceNames(name)] = serviceConfig + } + + handleVolume(&komposeObject, &composeObject.Volumes) + return komposeObject, nil +} + +func parseNetwork(composeServiceConfig *types.ServiceConfig, serviceConfig *kobject.ServiceConfig, composeObject *types.Project) error { + if len(composeServiceConfig.Networks) == 0 { + if defaultNetwork, ok := composeObject.Networks["default"]; ok { + normalizedNetworkName, err := normalizeNetworkNames(defaultNetwork.Name) + if err != nil { + return errors.Wrap(err, "Unable to normalize network name") + } + serviceConfig.Network = append(serviceConfig.Network, normalizedNetworkName) + } + } else { + var alias = "" + for key := range composeServiceConfig.Networks { + alias = key + netName := composeObject.Networks[alias].Name + + // if Network Name Field is empty in the docker-compose definition + // we will use the alias name defined in service config file + if netName == "" { + netName = alias + } + + normalizedNetworkName, err := normalizeNetworkNames(netName) + if err != nil { + return errors.Wrap(err, "Unable to normalize network name") + } + + serviceConfig.Network = append(serviceConfig.Network, normalizedNetworkName) + } + } + + return nil +} + +func parseResources(composeServiceConfig *types.ServiceConfig, serviceConfig *kobject.ServiceConfig) error { + serviceConfig.MemLimit = composeServiceConfig.MemLimit + + if composeServiceConfig.Deploy != nil { + // memory: + // See: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + // "The expression 0.1 is equivalent to the expression 100m, which can be read as “one hundred millicpu”." + + // Since Deploy.Resources.Limits does not initialize, we must check type Resources before continuing + if composeServiceConfig.Deploy.Resources.Limits != nil { + serviceConfig.MemLimit = composeServiceConfig.Deploy.Resources.Limits.MemoryBytes + + if composeServiceConfig.Deploy.Resources.Limits.NanoCPUs != "" { + cpuLimit, err := strconv.ParseFloat(composeServiceConfig.Deploy.Resources.Limits.NanoCPUs, 64) + if err != nil { + return errors.Wrap(err, "Unable to convert cpu limits resources value") + } + serviceConfig.CPULimit = int64(cpuLimit * 1000) + } + } + if composeServiceConfig.Deploy.Resources.Reservations != nil { + serviceConfig.MemReservation = composeServiceConfig.Deploy.Resources.Reservations.MemoryBytes + + if composeServiceConfig.Deploy.Resources.Reservations.NanoCPUs != "" { + cpuReservation, err := strconv.ParseFloat(composeServiceConfig.Deploy.Resources.Reservations.NanoCPUs, 64) + if err != nil { + return errors.Wrap(err, "Unable to convert cpu limits reservation value") + } + serviceConfig.CPUReservation = int64(cpuReservation * 1000) + } + } + } + return nil +} + +func parseEnvironment(composeServiceConfig *types.ServiceConfig, serviceConfig *kobject.ServiceConfig) { + // Gather the environment values + // DockerCompose uses map[string]*string while we use []string + // So let's convert that using this hack + // Note: unset env pick up the env value on host if exist + for name, value := range composeServiceConfig.Environment { + var env kobject.EnvVar + if value != nil { + env = kobject.EnvVar{Name: name, Value: *value} + } else { + result, ok := os.LookupEnv(name) + if ok { + env = kobject.EnvVar{Name: name, Value: result} + } else { + continue + } + } + serviceConfig.Environment = append(serviceConfig.Environment, env) } } -func getVersionFromFile(file string) (string, error) { - type ComposeVersion struct { - Version string `json:"version"` // This affects YAML as well - } - var version ComposeVersion - loadedFile, err := ReadFile(file) - - if err != nil { - return "", err +// parseKomposeLabels parse kompose labels, also do some validation +func parseKomposeLabels(labels map[string]string, serviceConfig *kobject.ServiceConfig) error { + // Label handler + // Labels used to influence conversion of kompose will be handled + // from here for docker-compose. Each loader will have such handler. + if serviceConfig.Labels == nil { + serviceConfig.Labels = make(map[string]string) } - err = yaml.Unmarshal(loadedFile, &version) - if err != nil { - return "", err + for key, value := range labels { + switch key { + case LabelServiceType: + serviceType, err := handleServiceType(value) + if err != nil { + return errors.Wrap(err, "handleServiceType failed") + } + + serviceConfig.ServiceType = serviceType + case LabelServiceExpose: + serviceConfig.ExposeService = strings.Trim(strings.ToLower(value), " ,") + case LabelNodePortPort: + serviceConfig.NodePortPort = cast.ToInt32(value) + case LabelServiceExposeTLSSecret: + serviceConfig.ExposeServiceTLS = value + case LabelServiceExposeIngressClassName: + serviceConfig.ExposeServiceIngressClassName = value + case LabelImagePullSecret: + serviceConfig.ImagePullSecret = value + case LabelImagePullPolicy: + serviceConfig.ImagePullPolicy = value + default: + serviceConfig.Labels[key] = value + } } - return version.Version, nil + if serviceConfig.ExposeService == "" && serviceConfig.ExposeServiceTLS != "" { + return errors.New("kompose.service.expose.tls-secret was specified without kompose.service.expose") + } + + if serviceConfig.ExposeService == "" && serviceConfig.ExposeServiceIngressClassName != "" { + return errors.New("kompose.service.expose.ingress-class-name was specified without kompose.service.expose") + } + + if serviceConfig.ServiceType != string(api.ServiceTypeNodePort) && serviceConfig.NodePortPort != 0 { + return errors.New("kompose.service.type must be nodeport when assign node port value") + } + + if len(serviceConfig.Port) > 1 && serviceConfig.NodePortPort != 0 { + return errors.New("cannot set kompose.service.nodeport.port when service has multiple ports") + } + + return nil +} + +func handleVolume(komposeObject *kobject.KomposeObject, volumes *types.Volumes) { + for name := range komposeObject.ServiceConfigs { + // retrieve volumes of service + vols, err := retrieveVolume(name, *komposeObject) + if err != nil { + errors.Wrap(err, "could not retrieve vvolume") + } + for volName, vol := range vols { + size, selector := getVolumeLabels(vol.VolumeName, volumes) + if len(size) > 0 || len(selector) > 0 { + // We can't assign value to struct field in map while iterating over it, so temporary variable `temp` is used here + var temp = vols[volName] + temp.PVCSize = size + temp.SelectorValue = selector + vols[volName] = temp + } + } + // We can't assign value to struct field in map while iterating over it, so temporary variable `temp` is used here + var temp = komposeObject.ServiceConfigs[name] + temp.Volumes = vols + komposeObject.ServiceConfigs[name] = temp + } +} + +// returns all volumes associated with service, if `volumes_from` key is used, we have to retrieve volumes from the services which are mentioned there. Hence, recursive function is used here. +func retrieveVolume(svcName string, komposeObject kobject.KomposeObject) (volume []kobject.Volumes, err error) { + // if volumes-from key is present + if komposeObject.ServiceConfigs[svcName].VolumesFrom != nil { + // iterating over services from `volumes-from` + for _, depSvc := range komposeObject.ServiceConfigs[svcName].VolumesFrom { + // recursive call for retrieving volumes of services from `volumes-from` + dVols, err := retrieveVolume(depSvc, komposeObject) + if err != nil { + return nil, errors.Wrapf(err, "could not retrieve the volume") + } + var cVols []kobject.Volumes + cVols, err = ParseVols(komposeObject.ServiceConfigs[svcName].VolList, svcName) + if err != nil { + return nil, errors.Wrapf(err, "error generating current volumes") + } + + for _, cv := range cVols { + // check whether volumes of current service is same or not as that of dependent volumes coming from `volumes-from` + ok, dv := getVol(cv, dVols) + if ok { + // change current volumes service name to dependent service name + if dv.VFrom == "" { + cv.VFrom = dv.SvcName + cv.SvcName = dv.SvcName + } else { + cv.VFrom = dv.VFrom + cv.SvcName = dv.SvcName + } + cv.PVCName = dv.PVCName + } + volume = append(volume, cv) + } + // iterating over dependent volumes + for _, dv := range dVols { + // check whether dependent volume is already present or not + if checkVolDependent(dv, volume) { + // if found, add service name to `VFrom` + dv.VFrom = dv.SvcName + volume = append(volume, dv) + } + } + } + } else { + // if `volumes-from` is not present + volume, err = ParseVols(komposeObject.ServiceConfigs[svcName].VolList, svcName) + if err != nil { + return nil, errors.Wrapf(err, "error generating current volumes") + } + } + return +} + +// checkVolDependent returns false if dependent volume is present +func checkVolDependent(dv kobject.Volumes, volume []kobject.Volumes) bool { + for _, vol := range volume { + if vol.PVCName == dv.PVCName { + return false + } + } + return true +} + +// ParseVols parse volumes +func ParseVols(volNames []string, svcName string) ([]kobject.Volumes, error) { + var volumes []kobject.Volumes + var err error + + for i, vn := range volNames { + var v kobject.Volumes + v.VolumeName, v.Host, v.Container, v.Mode, err = transformer.ParseVolume(vn) + if err != nil { + return nil, errors.Wrapf(err, "could not parse volume %q: %v", vn, err) + } + v.VolumeName = normalizeVolumes(v.VolumeName) + v.SvcName = svcName + v.MountPath = fmt.Sprintf("%s:%s", v.Host, v.Container) + v.PVCName = fmt.Sprintf("%s-claim%d", v.SvcName, i) + volumes = append(volumes, v) + } + + return volumes, nil +} + +// for dependent volumes, returns true and the respective volume if mountpath are same +func getVol(toFind kobject.Volumes, Vols []kobject.Volumes) (bool, kobject.Volumes) { + for _, dv := range Vols { + if toFind.MountPath == dv.MountPath { + return true, dv + } + } + return false, kobject.Volumes{} +} + +func getVolumeLabels(name string, volumes *types.Volumes) (string, string) { + size, selector := "", "" + + if volume, ok := (*volumes)[name]; ok { + for key, value := range volume.Labels { + if key == "kompose.volume.size" { + size = value + } else if key == "kompose.volume.selector" { + selector = value + } + } + } + + return size, selector +} + +// getGroupAdd will return group in int64 format +func getGroupAdd(group []string) ([]int64, error) { + var groupAdd []int64 + for _, i := range group { + j, err := strconv.Atoi(i) + if err != nil { + return nil, errors.Wrap(err, "unable to get group_add key") + } + groupAdd = append(groupAdd, int64(j)) + } + return groupAdd, nil } diff --git a/pkg/loader/compose/compose_test.go b/pkg/loader/compose/compose_test.go index 1f3b1cfc..0ba33a36 100644 --- a/pkg/loader/compose/compose_test.go +++ b/pkg/loader/compose/compose_test.go @@ -24,10 +24,7 @@ import ( "testing" "time" - "github.com/docker/cli/cli/compose/types" - "github.com/docker/libcompose/config" - "github.com/docker/libcompose/project" - "github.com/docker/libcompose/yaml" + "github.com/compose-spec/compose-go/types" "github.com/google/go-cmp/cmp" "github.com/kubernetes/kompose/pkg/kobject" "github.com/pkg/errors" @@ -203,7 +200,7 @@ func TestLoadV3Volumes(t *testing.T) { ReadOnly: true, } volumes := []types.ServiceVolumeConfig{vol} - output := loadV3Volumes(volumes) + output := loadVolumes(volumes) expected := "/tmp/foobar:/tmp/foobar:ro" if output[0] != expected { @@ -220,7 +217,7 @@ func TestLoadV3Ports(t *testing.T) { }{ { desc: "ports with expose", - ports: []types.ServicePortConfig{{Target: 80, Published: 80, Protocol: string(api.ProtocolTCP)}}, + ports: []types.ServicePortConfig{{Target: 80, Published: "80", Protocol: string(api.ProtocolTCP)}}, expose: []string{"80", "8080"}, want: []kobject.Ports{ {HostPort: 80, ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, @@ -229,7 +226,7 @@ func TestLoadV3Ports(t *testing.T) { }, { desc: "exposed port including /protocol", - ports: []types.ServicePortConfig{{Target: 80, Published: 80, Protocol: string(api.ProtocolTCP)}}, + ports: []types.ServicePortConfig{{Target: 80, Published: "80", Protocol: string(api.ProtocolTCP)}}, expose: []string{"80/udp"}, want: []kobject.Ports{ {HostPort: 80, ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, @@ -238,7 +235,7 @@ func TestLoadV3Ports(t *testing.T) { }, } { t.Run(tt.desc, func(t *testing.T) { - got := loadV3Ports(tt.ports, tt.expose) + got := loadPorts(tt.ports, tt.expose) if diff := cmp.Diff(tt.want, got); diff != "" { t.Errorf("loadV3Ports() mismatch (-want +got):\n%s", diff) } @@ -275,92 +272,90 @@ func TestHandleServiceType(t *testing.T) { // Test loading of ports func TestLoadPorts(t *testing.T) { + portWithIPAddress, _ := types.ParsePortConfig("127.0.0.1:80:80/tcp") + portWithoutIPAddress, _ := types.ParsePortConfig("80:80/tcp") + portWithoutProtocol, _ := types.ParsePortConfig("80:80") + singlePort, _ := types.ParsePortConfig("80") + singlePortsRange, _ := types.ParsePortConfig("3000-3002") + targetAndContainerPortsRange, _ := types.ParsePortConfig("3000-3002:5000-5002") + targetAndContainerPortsRangeWithIPAddress, _ := types.ParsePortConfig("127.0.0.1:3000-3002:5000-5002") + port3000, _ := types.ParsePortConfig("3000") + tests := []struct { - ports []string + ports []types.ServicePortConfig expose []string want []kobject.Ports }{ { - ports: []string{"127.0.0.1:80:80/tcp"}, + ports: portWithIPAddress, want: []kobject.Ports{ {HostIP: "127.0.0.1", HostPort: 80, ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, }, }, { - ports: []string{"80:80/tcp"}, + ports: portWithoutIPAddress, want: []kobject.Ports{ {HostPort: 80, ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, }, }, { - ports: []string{"80:80"}, + ports: portWithoutProtocol, want: []kobject.Ports{ {HostPort: 80, ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, }, }, { - ports: []string{"80"}, + ports: singlePort, want: []kobject.Ports{ {ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, }, }, { - ports: []string{"3000-3005"}, + ports: singlePortsRange, want: []kobject.Ports{ {ContainerPort: 3000, Protocol: string(api.ProtocolTCP)}, {ContainerPort: 3001, Protocol: string(api.ProtocolTCP)}, {ContainerPort: 3002, Protocol: string(api.ProtocolTCP)}, - {ContainerPort: 3003, Protocol: string(api.ProtocolTCP)}, - {ContainerPort: 3004, Protocol: string(api.ProtocolTCP)}, - {ContainerPort: 3005, Protocol: string(api.ProtocolTCP)}, }, }, { - ports: []string{"3000-3005:5000-5005"}, + ports: targetAndContainerPortsRange, want: []kobject.Ports{ {HostPort: 3000, ContainerPort: 5000, Protocol: string(api.ProtocolTCP)}, {HostPort: 3001, ContainerPort: 5001, Protocol: string(api.ProtocolTCP)}, {HostPort: 3002, ContainerPort: 5002, Protocol: string(api.ProtocolTCP)}, - {HostPort: 3003, ContainerPort: 5003, Protocol: string(api.ProtocolTCP)}, - {HostPort: 3004, ContainerPort: 5004, Protocol: string(api.ProtocolTCP)}, - {HostPort: 3005, ContainerPort: 5005, Protocol: string(api.ProtocolTCP)}, }, }, { - ports: []string{"127.0.0.1:3000-3005:5000-5005"}, + ports: targetAndContainerPortsRangeWithIPAddress, want: []kobject.Ports{ {HostIP: "127.0.0.1", HostPort: 3000, ContainerPort: 5000, Protocol: string(api.ProtocolTCP)}, {HostIP: "127.0.0.1", HostPort: 3001, ContainerPort: 5001, Protocol: string(api.ProtocolTCP)}, {HostIP: "127.0.0.1", HostPort: 3002, ContainerPort: 5002, Protocol: string(api.ProtocolTCP)}, - {HostIP: "127.0.0.1", HostPort: 3003, ContainerPort: 5003, Protocol: string(api.ProtocolTCP)}, - {HostIP: "127.0.0.1", HostPort: 3004, ContainerPort: 5004, Protocol: string(api.ProtocolTCP)}, - {HostIP: "127.0.0.1", HostPort: 3005, ContainerPort: 5005, Protocol: string(api.ProtocolTCP)}, }, }, { - ports: []string{"80", "3000"}, + ports: append(append([]types.ServicePortConfig{}, singlePort...), port3000...), want: []kobject.Ports{ {HostPort: 0, ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, {HostPort: 0, ContainerPort: 3000, Protocol: string(api.ProtocolTCP)}, }, }, { - ports: []string{"80", "3000"}, + ports: append(append([]types.ServicePortConfig{}, singlePort...), port3000...), expose: []string{"80", "8080"}, want: []kobject.Ports{ - {HostPort: 0, ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, - {HostPort: 0, ContainerPort: 3000, Protocol: string(api.ProtocolTCP)}, - {HostPort: 0, ContainerPort: 8080, Protocol: string(api.ProtocolTCP)}, + {ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, + {ContainerPort: 3000, Protocol: string(api.ProtocolTCP)}, + {HostPort: 80, ContainerPort: 80, Protocol: string(api.ProtocolTCP)}, + {HostPort: 8080, ContainerPort: 8080, Protocol: string(api.ProtocolTCP)}, }, }, } for _, tt := range tests { t.Run(fmt.Sprintf("port=%q,expose=%q", tt.ports, tt.expose), func(t *testing.T) { - got, err := loadPorts(tt.ports, tt.expose) - if err != nil { - t.Fatalf("Unexpected error with loading ports %v", err) - } + got := loadPorts(tt.ports, tt.expose) if diff := cmp.Diff(tt.want, got); diff != "" { t.Errorf("loadPorts() mismatch (-want +got):\n%s", diff) } @@ -438,71 +433,60 @@ func TestLoadEnvVar(t *testing.T) { // docker-compose projects func TestUnsupportedKeys(t *testing.T) { // create project that will be used in test cases - projectWithNetworks := project.NewProject(&project.Context{}, nil, nil) - projectWithNetworks.ServiceConfigs = config.NewServiceConfigs() - projectWithNetworks.ServiceConfigs.Add("foo", &config.ServiceConfig{ - Image: "foo/bar", - Build: yaml.Build{ - Context: "./build", + projectWithNetworks := &types.Project{ + Networks: types.Networks{ + "foo": types.NetworkConfig{ + Name: "foo", + Driver: "bridge", + }, }, - Hostname: "localhost", - Ports: []string{}, // test empty array - Networks: &yaml.Networks{ - Networks: []*yaml.Network{ - { - Name: "net1", + Services: types.Services{ + types.ServiceConfig{ + Name: "foo", + Image: "foo/bar", + Build: &types.BuildConfig{ + Context: "./build", + }, + Hostname: "localhost", + Ports: []types.ServicePortConfig{}, // test empty array + Networks: map[string]*types.ServiceNetworkConfig{ + "net1": {}, + }, + }, + types.ServiceConfig{ + Name: "bar", + Image: "bar/foo", + Build: &types.BuildConfig{ + Context: "./build", + }, + Hostname: "localhost", + Ports: []types.ServicePortConfig{}, // test empty array + Networks: map[string]*types.ServiceNetworkConfig{ + "net1": {}, }, }, }, - }) - projectWithNetworks.ServiceConfigs.Add("bar", &config.ServiceConfig{ - Image: "bar/foo", - Build: yaml.Build{ - Context: "./build", - }, - Hostname: "localhost", - Ports: []string{}, // test empty array - Networks: &yaml.Networks{ - Networks: []*yaml.Network{ - { - Name: "net1", - }, + Volumes: types.Volumes{ + "foo": types.VolumeConfig{ + Name: "foo", + Driver: "storage", }, }, - }) - projectWithNetworks.VolumeConfigs = map[string]*config.VolumeConfig{ - "foo": { - Driver: "storage", - }, - } - projectWithNetworks.NetworkConfigs = map[string]*config.NetworkConfig{ - "foo": { - Driver: "bridge", - }, } - projectWithEmptyNetwork := project.NewProject(&project.Context{}, nil, nil) - projectWithEmptyNetwork.ServiceConfigs = config.NewServiceConfigs() - projectWithEmptyNetwork.ServiceConfigs.Add("foo", &config.ServiceConfig{ - Networks: &yaml.Networks{}, - }) - - projectWithDefaultNetwork := project.NewProject(&project.Context{}, nil, nil) - projectWithDefaultNetwork.ServiceConfigs = config.NewServiceConfigs() - - projectWithDefaultNetwork.ServiceConfigs.Add("foo", &config.ServiceConfig{ - Networks: &yaml.Networks{ - Networks: []*yaml.Network{ - { - Name: "default", + projectWithDefaultNetwork := &types.Project{ + Services: types.Services{ + types.ServiceConfig{ + Networks: map[string]*types.ServiceNetworkConfig{ + "default": {}, }, }, }, - }) + } // define all test cases for checkUnsupportedKey function testCases := map[string]struct { - composeProject *project.Project + composeProject *types.Project expectedUnsupportedKeys []string }{ "With Networks (service and root level)": { @@ -567,28 +551,6 @@ func TestNormalizeNetworkNames(t *testing.T) { } } -func TestCheckLabelsPorts(t *testing.T) { - testCases := []struct { - name string - noOfPort int - labels string - svcName string - expectError bool - }{ - {"ports is defined", 1, "NodePort", "foo", false}, - {"ports is not defined", 0, "NodePort", "foo", true}, - } - - var err error - for _, testcase := range testCases { - t.Log(testcase.name) - err = checkLabelsPorts(testcase.noOfPort, testcase.labels, testcase.svcName) - if testcase.expectError && err == nil { - t.Log("Expected error, got ", err) - } - } -} - func TestCheckPlacementCustomLabels(t *testing.T) { placement := types.Placement{ Constraints: []string{ @@ -601,7 +563,7 @@ func TestCheckPlacementCustomLabels(t *testing.T) { {Spread: "node.labels.ssd"}, }, } - output := loadV3Placement(placement) + output := loadPlacement(placement) expected := kobject.Placement{ PositiveConstraints: map[string]string{ diff --git a/pkg/loader/compose/v1v2.go b/pkg/loader/compose/v1v2.go deleted file mode 100644 index aff7c53f..00000000 --- a/pkg/loader/compose/v1v2.go +++ /dev/null @@ -1,417 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package compose - -import ( - "fmt" - "net" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - - "github.com/docker/cli/opts" - "github.com/docker/go-connections/nat" - "github.com/docker/libcompose/config" - "github.com/docker/libcompose/lookup" - "github.com/docker/libcompose/project" - "github.com/kubernetes/kompose/pkg/kobject" - "github.com/kubernetes/kompose/pkg/transformer" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" - "github.com/spf13/cast" - api "k8s.io/api/core/v1" -) - -// Parse Docker Compose with libcompose (only supports v1 and v2). Eventually we will -// switch to using only libcompose once v3 is supported. -func parseV1V2(files []string) (kobject.KomposeObject, error) { - // Gather the appropriate context for parsing - context := &project.Context{} - context.ComposeFiles = files - - if context.ResourceLookup == nil { - context.ResourceLookup = &lookup.FileResourceLookup{} - } - - if context.EnvironmentLookup == nil { - cwd, err := os.Getwd() - if err != nil { - return kobject.KomposeObject{}, nil - } - context.EnvironmentLookup = &lookup.ComposableEnvLookup{ - Lookups: []config.EnvironmentLookup{ - &lookup.EnvfileLookup{ - Path: filepath.Join(cwd, ".env"), - }, - &lookup.OsEnvLookup{}, - }, - } - } - - // Load the context and let's start parsing - composeObject := project.NewProject(context, nil, nil) - err := composeObject.Parse() - if err != nil { - return kobject.KomposeObject{}, errors.Wrap(err, "composeObject.Parse() failed, Failed to load compose file") - } - - noSupKeys := checkUnsupportedKey(composeObject) - for _, keyName := range noSupKeys { - log.Warningf("Unsupported %s key - ignoring", keyName) - } - - // Map the parsed struct to a struct we understand (kobject) - komposeObject, err := libComposeToKomposeMapping(composeObject) - if err != nil { - return kobject.KomposeObject{}, err - } - - return komposeObject, nil -} - -// Load ports from compose file -// also load `expose` here -func loadPorts(composePorts []string, expose []string) ([]kobject.Ports, error) { - kp := []kobject.Ports{} - exist := map[string]bool{} - for _, cp := range composePorts { - var hostIP string - - if parts := strings.Split(cp, ":"); len(parts) == 3 { - if ip := net.ParseIP(parts[0]); ip.To4() == nil && ip.To16() == nil { - return nil, fmt.Errorf("%q contains an invalid IPv4 or IPv6 IP address", parts[0]) - } - hostIP = parts[0] - } - - np, pbs, err := nat.ParsePortSpecs([]string{cp}) - if err != nil { - return nil, fmt.Errorf("invalid port, error = %v", err) - } - // Force HostIP value to avoid warning raised by github.com/docker/cli/opts - // The opts package will warn if the bindings contains host IP except - // 0.0.0.0. However, the message is not useful in this case since the value - // should be handled by kompose properly. - for _, pb := range pbs { - for i, p := range pb { - p.HostIP = "" - pb[i] = p - } - } - - var ports []string - for p := range np { - ports = append(ports, string(p)) - } - sort.Strings(ports) - - for _, p := range ports { - pc, err := opts.ConvertPortToPortConfig(nat.Port(p), pbs) - if err != nil { - return nil, fmt.Errorf("invalid port, error = %v", err) - } - for _, cfg := range pc { - kp = append(kp, kobject.Ports{ - HostPort: int32(cfg.PublishedPort), - ContainerPort: int32(cfg.TargetPort), - HostIP: hostIP, - Protocol: strings.ToUpper(string(cfg.Protocol)), - }) - } - } - } - - // load remain expose ports - for _, p := range kp { - // must use cast... - exist[cast.ToString(p.ContainerPort)+p.Protocol] = true - } - - if expose != nil { - for _, port := range expose { - portValue := port - protocol := string(api.ProtocolTCP) - if strings.Contains(portValue, "/") { - splits := strings.Split(port, "/") - portValue = splits[0] - protocol = splits[1] - } - - if !exist[portValue+protocol] { - kp = append(kp, kobject.Ports{ - ContainerPort: cast.ToInt32(portValue), - Protocol: strings.ToUpper(protocol), - }) - } - } - } - - return kp, nil -} - -// Uses libcompose's APIProject type and converts it to a Kompose object for us to understand -func libComposeToKomposeMapping(composeObject *project.Project) (kobject.KomposeObject, error) { - // Initialize what's going to be returned - komposeObject := kobject.KomposeObject{ - ServiceConfigs: make(map[string]kobject.ServiceConfig), - LoadedFrom: "compose", - } - - // Here we "clean up" the service configuration so we return something that includes - // all relevant information as well as avoid the unsupported keys as well. - for name, composeServiceConfig := range composeObject.ServiceConfigs.All() { - serviceConfig := kobject.ServiceConfig{} - serviceConfig.Name = name - serviceConfig.Image = composeServiceConfig.Image - serviceConfig.Build = composeServiceConfig.Build.Context - newName := normalizeContainerNames(composeServiceConfig.ContainerName) - serviceConfig.ContainerName = newName - if newName != composeServiceConfig.ContainerName { - log.Infof("Container name in service %q has been changed from %q to %q", name, composeServiceConfig.ContainerName, newName) - } - serviceConfig.Command = composeServiceConfig.Entrypoint - serviceConfig.HostName = composeServiceConfig.Hostname - serviceConfig.DomainName = composeServiceConfig.DomainName - serviceConfig.Args = composeServiceConfig.Command - serviceConfig.Dockerfile = composeServiceConfig.Build.Dockerfile - serviceConfig.BuildArgs = composeServiceConfig.Build.Args - serviceConfig.Expose = composeServiceConfig.Expose - - envs := loadEnvVars(composeServiceConfig.Environment) - serviceConfig.Environment = envs - - // Validate dockerfile path - if filepath.IsAbs(serviceConfig.Dockerfile) { - log.Fatalf("%q defined in service %q is an absolute path, it must be a relative path.", serviceConfig.Dockerfile, name) - } - - // load ports, same as v3, we also load `expose` - ports, err := loadPorts(composeServiceConfig.Ports, serviceConfig.Expose) - if err != nil { - return kobject.KomposeObject{}, errors.Wrap(err, "loadPorts failed. "+name+" failed to load ports from compose file") - } - serviceConfig.Port = ports - - serviceConfig.WorkingDir = composeServiceConfig.WorkingDir - - if composeServiceConfig.Volumes != nil { - for _, volume := range composeServiceConfig.Volumes.Volumes { - v := volume.String() - serviceConfig.VolList = append(serviceConfig.VolList, v) - } - } - - // canonical "Custom Labels" handler - // Labels used to influence conversion of kompose will be handled - // from here for docker-compose. Each loader will have such handler. - if err := parseKomposeLabels(composeServiceConfig.Labels, &serviceConfig); err != nil { - return kobject.KomposeObject{}, err - } - - err = checkLabelsPorts(len(serviceConfig.Port), composeServiceConfig.Labels[LabelServiceType], name) - if err != nil { - return kobject.KomposeObject{}, errors.Wrap(err, "kompose.service.type can't be set if service doesn't expose any ports.") - } - - // convert compose labels to annotations - serviceConfig.Annotations = composeServiceConfig.Labels - serviceConfig.CPUQuota = int64(composeServiceConfig.CPUQuota) - serviceConfig.CapAdd = composeServiceConfig.CapAdd - serviceConfig.CapDrop = composeServiceConfig.CapDrop - serviceConfig.Pid = composeServiceConfig.Pid - - serviceConfig.Privileged = composeServiceConfig.Privileged - serviceConfig.User = composeServiceConfig.User - serviceConfig.VolumesFrom = composeServiceConfig.VolumesFrom - serviceConfig.Stdin = composeServiceConfig.StdinOpen - serviceConfig.Tty = composeServiceConfig.Tty - serviceConfig.MemLimit = composeServiceConfig.MemLimit - serviceConfig.TmpFs = composeServiceConfig.Tmpfs - serviceConfig.StopGracePeriod = composeServiceConfig.StopGracePeriod - - // pretty much same as v3 - serviceConfig.Restart = composeServiceConfig.Restart - if serviceConfig.Restart == "unless-stopped" { - log.Warnf("Restart policy 'unless-stopped' in service %s is not supported, convert it to 'always'", name) - serviceConfig.Restart = "always" - } - - if composeServiceConfig.Networks != nil { - if len(composeServiceConfig.Networks.Networks) > 0 { - for _, value := range composeServiceConfig.Networks.Networks { - if value.Name != "default" { - nomalizedNetworkName, err := normalizeNetworkNames(value.RealName) - if err != nil { - return kobject.KomposeObject{}, errors.Wrap(err, "Error trying to normalize network names") - } - if nomalizedNetworkName != value.RealName { - log.Warnf("Network name in docker-compose has been changed from %q to %q", value.RealName, nomalizedNetworkName) - } - serviceConfig.Network = append(serviceConfig.Network, nomalizedNetworkName) - } - } - } - } - // Get GroupAdd, group should be mentioned in gid format but not the group name - groupAdd, err := getGroupAdd(composeServiceConfig.GroupAdd) - if err != nil { - return kobject.KomposeObject{}, errors.Wrap(err, "GroupAdd should be mentioned in gid format, not a group name") - } - serviceConfig.GroupAdd = groupAdd - - komposeObject.ServiceConfigs[normalizeServiceNames(name)] = serviceConfig - if normalizeServiceNames(name) != name { - log.Infof("Service name in docker-compose has been changed from %q to %q", name, normalizeServiceNames(name)) - } - } - - // This will handle volume at earlier stage itself, it will resolves problems occurred due to `volumes_from` key - handleVolume(&komposeObject) - - return komposeObject, nil -} - -// This function will retrieve volumes for each service, as well as it will parse volume information and store it in Volumes struct -func handleVolume(komposeObject *kobject.KomposeObject) { - for name := range komposeObject.ServiceConfigs { - // retrieve volumes of service - vols, err := retrieveVolume(name, *komposeObject) - if err != nil { - errors.Wrap(err, "could not retrieve volume") - } - // We can't assign value to struct field in map while iterating over it, so temporary variable `temp` is used here - var temp = komposeObject.ServiceConfigs[name] - temp.Volumes = vols - komposeObject.ServiceConfigs[name] = temp - } -} - -func checkLabelsPorts(noOfPort int, labels string, svcName string) error { - if noOfPort == 0 && (labels == "NodePort" || labels == "LoadBalancer") { - return errors.Errorf("%s defined in service %s with no ports present. Issues may occur when bringing up artifacts.", labels, svcName) - } - return nil -} - -// returns all volumes associated with service, if `volumes_from` key is used, we have to retrieve volumes from the services which are mentioned there. Hence, recursive function is used here. -func retrieveVolume(svcName string, komposeObject kobject.KomposeObject) (volume []kobject.Volumes, err error) { - // if volumes-from key is present - if komposeObject.ServiceConfigs[svcName].VolumesFrom != nil { - // iterating over services from `volumes-from` - for _, depSvc := range komposeObject.ServiceConfigs[svcName].VolumesFrom { - // recursive call for retrieving volumes of services from `volumes-from` - dVols, err := retrieveVolume(depSvc, komposeObject) - if err != nil { - return nil, errors.Wrapf(err, "could not retrieve the volume") - } - var cVols []kobject.Volumes - cVols, err = ParseVols(komposeObject.ServiceConfigs[svcName].VolList, svcName) - if err != nil { - return nil, errors.Wrapf(err, "error generating current volumes") - } - - for _, cv := range cVols { - // check whether volumes of current service is same or not as that of dependent volumes coming from `volumes-from` - ok, dv := getVol(cv, dVols) - if ok { - // change current volumes service name to dependent service name - if dv.VFrom == "" { - cv.VFrom = dv.SvcName - cv.SvcName = dv.SvcName - } else { - cv.VFrom = dv.VFrom - cv.SvcName = dv.SvcName - } - cv.PVCName = dv.PVCName - } - volume = append(volume, cv) - } - // iterating over dependent volumes - for _, dv := range dVols { - // check whether dependent volume is already present or not - if checkVolDependent(dv, volume) { - // if found, add service name to `VFrom` - dv.VFrom = dv.SvcName - volume = append(volume, dv) - } - } - } - } else { - // if `volumes-from` is not present - volume, err = ParseVols(komposeObject.ServiceConfigs[svcName].VolList, svcName) - if err != nil { - return nil, errors.Wrapf(err, "error generating current volumes") - } - } - return -} - -// checkVolDependent returns false if dependent volume is present -func checkVolDependent(dv kobject.Volumes, volume []kobject.Volumes) bool { - for _, vol := range volume { - if vol.PVCName == dv.PVCName { - return false - } - } - return true -} - -// ParseVols parse volumes -func ParseVols(volNames []string, svcName string) ([]kobject.Volumes, error) { - var volumes []kobject.Volumes - var err error - - for i, vn := range volNames { - var v kobject.Volumes - v.VolumeName, v.Host, v.Container, v.Mode, err = transformer.ParseVolume(vn) - if err != nil { - return nil, errors.Wrapf(err, "could not parse volume %q: %v", vn, err) - } - v.VolumeName = normalizeVolumes(v.VolumeName) - v.SvcName = svcName - v.MountPath = fmt.Sprintf("%s:%s", v.Host, v.Container) - v.PVCName = fmt.Sprintf("%s-claim%d", v.SvcName, i) - volumes = append(volumes, v) - } - - return volumes, nil -} - -// for dependent volumes, returns true and the respective volume if mountpath are same -func getVol(toFind kobject.Volumes, Vols []kobject.Volumes) (bool, kobject.Volumes) { - for _, dv := range Vols { - if toFind.MountPath == dv.MountPath { - return true, dv - } - } - return false, kobject.Volumes{} -} - -// getGroupAdd will return group in int64 format -func getGroupAdd(group []string) ([]int64, error) { - var groupAdd []int64 - for _, i := range group { - j, err := strconv.Atoi(i) - if err != nil { - return nil, errors.Wrap(err, "unable to get group_add key") - } - groupAdd = append(groupAdd, int64(j)) - } - return groupAdd, nil -} diff --git a/pkg/loader/compose/v3.go b/pkg/loader/compose/v3.go deleted file mode 100644 index e1b58a9f..00000000 --- a/pkg/loader/compose/v3.go +++ /dev/null @@ -1,1009 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package compose - -import ( - "fmt" - "os" - "path" - "strconv" - "strings" - "time" - - "github.com/spf13/cast" - - libcomposeyaml "github.com/docker/libcompose/yaml" - - api "k8s.io/api/core/v1" - - "github.com/docker/cli/cli/compose/loader" - "github.com/docker/cli/cli/compose/types" - - "github.com/google/shlex" - "github.com/kubernetes/kompose/pkg/kobject" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" -) - -// converts os.Environ() ([]string) to map[string]string -// based on https://github.com/docker/cli/blob/5dd30732a23bbf14db1c64d084ae4a375f592cfa/cli/command/stack/deploy_composefile.go#L143 -func buildEnvironment() (map[string]string, error) { - env := os.Environ() - result := make(map[string]string, len(env)) - for _, s := range env { - // if value is empty, s is like "K=", not "K". - if !strings.Contains(s, "=") { - return result, errors.Errorf("unexpected environment %q", s) - } - kv := strings.SplitN(s, "=", 2) - result[kv[0]] = kv[1] - } - return result, nil -} - -// The purpose of this is not to deploy, but to be able to parse -// v3 of Docker Compose into a suitable format. In this case, whatever is returned -// by docker/cli's ServiceConfig -func parseV3(files []string) (kobject.KomposeObject, error) { - // In order to get V3 parsing to work, we have to go through some preliminary steps - // for us to hack up github.com/docker/cli in order to correctly convert to a kobject.KomposeObject - - // Gather the working directory - workingDir, err := getComposeFileDir(files) - if err != nil { - return kobject.KomposeObject{}, err - } - - // get environment variables - env, err := buildEnvironment() - if err != nil { - return kobject.KomposeObject{}, errors.Wrap(err, "cannot build environment variables") - } - - var config *types.Config - for _, file := range files { - // Load and then parse the YAML first! - loadedFile, err := ReadFile(file) - if err != nil { - return kobject.KomposeObject{}, err - } - - // Parse the Compose File - parsedComposeFile, err := loader.ParseYAML(loadedFile) - if err != nil { - return kobject.KomposeObject{}, err - } - - // Config file - configFile := types.ConfigFile{ - Filename: file, - Config: parsedComposeFile, - } - - // Config details - configDetails := types.ConfigDetails{ - WorkingDir: workingDir, - ConfigFiles: []types.ConfigFile{configFile}, - Environment: env, - } - - // Actual config - // We load it in order to retrieve the parsed output configuration! - // This will output a github.com/docker/cli ServiceConfig - // Which is similar to our version of ServiceConfig - currentConfig, err := loader.Load(configDetails, func(options *loader.Options) { - options.SkipInterpolation = true - }) - if err != nil { - return kobject.KomposeObject{}, err - } - if config == nil { - config = currentConfig - } else { - config, err = mergeComposeObject(config, currentConfig) - if err != nil { - return kobject.KomposeObject{}, err - } - } - } - - noSupKeys := checkUnsupportedKeyForV3(config) - for _, keyName := range noSupKeys { - log.Warningf("Unsupported %s key - ignoring", keyName) - } - - // Finally, we convert the object from docker/cli's ServiceConfig to our appropriate one - komposeObject, err := dockerComposeToKomposeMapping(config) - if err != nil { - return kobject.KomposeObject{}, err - } - return komposeObject, nil -} - -func loadV3Placement(placement types.Placement) kobject.Placement { - komposePlacement := kobject.Placement{ - PositiveConstraints: make(map[string]string), - NegativeConstraints: make(map[string]string), - Preferences: make([]string, 0, len(placement.Preferences)), - } - - // Convert constraints - equal, notEqual := " == ", " != " - for _, j := range placement.Constraints { - operator := equal - if strings.Contains(j, notEqual) { - operator = notEqual - } - p := strings.Split(j, operator) - if len(p) < 2 { - log.Warnf("Failed to parse placement constraints %s, the correct format is 'label == xxx'", j) - continue - } - - key, err := convertDockerLabel(p[0]) - if err != nil { - log.Warn("Ignore placement constraints: ", err.Error()) - continue - } - - if operator == equal { - komposePlacement.PositiveConstraints[key] = p[1] - } else if operator == notEqual { - komposePlacement.NegativeConstraints[key] = p[1] - } - } - - // Convert preferences - for _, p := range placement.Preferences { - // Spread is the only supported strategy currently - label, err := convertDockerLabel(p.Spread) - if err != nil { - log.Warn("Ignore placement preferences: ", err.Error()) - continue - } - komposePlacement.Preferences = append(komposePlacement.Preferences, label) - } - return komposePlacement -} - -// Convert docker label to k8s label -func convertDockerLabel(dockerLabel string) (string, error) { - switch dockerLabel { - case "node.hostname": - return "kubernetes.io/hostname", nil - case "engine.labels.operatingsystem": - return "kubernetes.io/os", nil - default: - if strings.HasPrefix(dockerLabel, "node.labels.") { - return strings.TrimPrefix(dockerLabel, "node.labels."), nil - } - } - errMsg := fmt.Sprint(dockerLabel, " is not supported, only 'node.hostname', 'engine.labels.operatingsystem' and 'node.labels.xxx' (ex: node.labels.something == anything) is supported") - return "", errors.New(errMsg) -} - -// Convert the Docker Compose v3 volumes to []string (the old way) -// TODO: Check to see if it's a "bind" or "volume". Ignore for now. -// TODO: Refactor it similar to loadV3Ports -// See: https://docs.docker.com/compose/compose-file/#long-syntax-3 -func loadV3Volumes(volumes []types.ServiceVolumeConfig) []string { - var volArray []string - for _, vol := range volumes { - // There will *always* be Source when parsing - v := vol.Source - - if vol.Target != "" { - v = v + ":" + vol.Target - } - - if vol.ReadOnly { - v = v + ":ro" - } - - volArray = append(volArray, v) - } - return volArray -} - -// Convert Docker Compose v3 ports to kobject.Ports -// expose ports will be treated as TCP ports -func loadV3Ports(ports []types.ServicePortConfig, expose []string) []kobject.Ports { - komposePorts := []kobject.Ports{} - exist := map[string]bool{} - - for _, port := range ports { - // Convert to a kobject struct with ports - // NOTE: V3 doesn't use IP (they utilize Swarm instead for host-networking). - // Thus, IP is blank. - komposePorts = append(komposePorts, kobject.Ports{ - HostPort: int32(port.Published), - ContainerPort: int32(port.Target), - HostIP: "", - Protocol: strings.ToUpper(port.Protocol), - }) - exist[cast.ToString(port.Target)+port.Protocol] = true - } - - if expose != nil { - for _, port := range expose { - portValue := port - protocol := string(api.ProtocolTCP) - if strings.Contains(portValue, "/") { - splits := strings.Split(port, "/") - portValue = splits[0] - protocol = splits[1] - } - - if exist[portValue+protocol] { - continue - } - komposePorts = append(komposePorts, kobject.Ports{ - HostPort: cast.ToInt32(portValue), - ContainerPort: cast.ToInt32(portValue), - HostIP: "", - Protocol: strings.ToUpper(protocol), - }) - } - } - - return komposePorts -} - -/* Convert the HealthCheckConfig as designed by Docker to -a Kubernetes-compatible format. -*/ -func parseHealthCheckReadiness(labels types.Labels) (kobject.HealthCheck, error) { - var test []string - var httpPath string - var httpPort, tcpPort, timeout, interval, retries, startPeriod int32 - var disable bool - - for key, value := range labels { - switch key { - case HealthCheckReadinessDisable: - disable = cast.ToBool(value) - case HealthCheckReadinessTest: - if len(value) > 0 { - test, _ = shlex.Split(value) - } - case HealthCheckReadinessHTTPGetPath: - httpPath = value - case HealthCheckReadinessHTTPGetPort: - httpPort = cast.ToInt32(value) - case HealthCheckReadinessTCPPort: - tcpPort = cast.ToInt32(value) - case HealthCheckReadinessInterval: - parse, err := time.ParseDuration(value) - if err != nil { - return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check interval variable") - } - interval = int32(parse.Seconds()) - case HealthCheckReadinessTimeout: - parse, err := time.ParseDuration(value) - if err != nil { - return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check timeout variable") - } - timeout = int32(parse.Seconds()) - case HealthCheckReadinessRetries: - retries = cast.ToInt32(value) - case HealthCheckReadinessStartPeriod: - parse, err := time.ParseDuration(value) - if err != nil { - return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check startPeriod variable") - } - startPeriod = int32(parse.Seconds()) - } - } - - if len(test) > 0 { - if test[0] == "NONE" { - disable = true - test = test[1:] - } - // Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test - if test[0] == "CMD" || test[0] == "CMD-SHELL" { - test = test[1:] - } - } - - return kobject.HealthCheck{ - Test: test, - HTTPPath: httpPath, - HTTPPort: httpPort, - TCPPort: tcpPort, - Timeout: timeout, - Interval: interval, - Retries: retries, - StartPeriod: startPeriod, - Disable: disable, - }, nil -} - -/* Convert the HealthCheckConfig as designed by Docker to -a Kubernetes-compatible format. -*/ -func parseHealthCheck(composeHealthCheck types.HealthCheckConfig, labels types.Labels) (kobject.HealthCheck, error) { - var httpPort, tcpPort, timeout, interval, retries, startPeriod int32 - var test []string - var httpPath string - - // Here we convert the timeout from 1h30s (example) to 36030 seconds. - if composeHealthCheck.Timeout != nil { - parse, err := time.ParseDuration(composeHealthCheck.Timeout.String()) - if err != nil { - return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check timeout variable") - } - timeout = int32(parse.Seconds()) - } - - if composeHealthCheck.Interval != nil { - parse, err := time.ParseDuration(composeHealthCheck.Interval.String()) - if err != nil { - return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check interval variable") - } - interval = int32(parse.Seconds()) - } - - if composeHealthCheck.Retries != nil { - retries = int32(*composeHealthCheck.Retries) - } - - if composeHealthCheck.StartPeriod != nil { - parse, err := time.ParseDuration(composeHealthCheck.StartPeriod.String()) - if err != nil { - return kobject.HealthCheck{}, errors.Wrap(err, "unable to parse health check startPeriod variable") - } - startPeriod = int32(parse.Seconds()) - } - - if composeHealthCheck.Test != nil { - test = composeHealthCheck.Test[1:] - } - - for key, value := range labels { - switch key { - case HealthCheckLivenessHTTPGetPath: - httpPath = value - case HealthCheckLivenessHTTPGetPort: - httpPort = cast.ToInt32(value) - case HealthCheckLivenessTCPPort: - tcpPort = cast.ToInt32(value) - } - } - - // Due to docker/cli adding "CMD-SHELL" to the struct, we remove the first element of composeHealthCheck.Test - return kobject.HealthCheck{ - Test: test, - TCPPort: tcpPort, - HTTPPath: httpPath, - HTTPPort: httpPort, - Timeout: timeout, - Interval: interval, - Retries: retries, - StartPeriod: startPeriod, - }, nil -} - -func dockerComposeToKomposeMapping(composeObject *types.Config) (kobject.KomposeObject, error) { - // Step 1. Initialize what's going to be returned - komposeObject := kobject.KomposeObject{ - ServiceConfigs: make(map[string]kobject.ServiceConfig), - LoadedFrom: "compose", - Secrets: composeObject.Secrets, - } - - // Step 2. Parse through the object and convert it to kobject.KomposeObject! - // Here we "clean up" the service configuration so we return something that includes - // all relevant information as well as avoid the unsupported keys as well. - for _, composeServiceConfig := range composeObject.Services { - // Standard import - // No need to modify before importation - name := composeServiceConfig.Name - serviceConfig := kobject.ServiceConfig{} - serviceConfig.Name = name - serviceConfig.Image = composeServiceConfig.Image - serviceConfig.WorkingDir = composeServiceConfig.WorkingDir - serviceConfig.Annotations = composeServiceConfig.Labels - serviceConfig.CapAdd = composeServiceConfig.CapAdd - serviceConfig.CapDrop = composeServiceConfig.CapDrop - serviceConfig.Expose = composeServiceConfig.Expose - serviceConfig.Privileged = composeServiceConfig.Privileged - serviceConfig.User = composeServiceConfig.User - serviceConfig.Stdin = composeServiceConfig.StdinOpen - serviceConfig.Tty = composeServiceConfig.Tty - serviceConfig.TmpFs = composeServiceConfig.Tmpfs - serviceConfig.ContainerName = normalizeContainerNames(composeServiceConfig.ContainerName) - serviceConfig.Command = composeServiceConfig.Entrypoint - serviceConfig.Args = composeServiceConfig.Command - serviceConfig.Labels = composeServiceConfig.Labels - serviceConfig.HostName = composeServiceConfig.Hostname - serviceConfig.DomainName = composeServiceConfig.DomainName - serviceConfig.Secrets = composeServiceConfig.Secrets - - if composeServiceConfig.StopGracePeriod != nil { - serviceConfig.StopGracePeriod = composeServiceConfig.StopGracePeriod.String() - } - - if err := parseV3Network(&composeServiceConfig, &serviceConfig, composeObject); err != nil { - return kobject.KomposeObject{}, err - } - - if err := parseV3Resources(&composeServiceConfig, &serviceConfig); err != nil { - return kobject.KomposeObject{}, err - } - - // Deploy keys - // mode: - serviceConfig.DeployMode = composeServiceConfig.Deploy.Mode - // labels - serviceConfig.DeployLabels = composeServiceConfig.Deploy.Labels - - // HealthCheck Liveness - if composeServiceConfig.HealthCheck != nil && !composeServiceConfig.HealthCheck.Disable { - var err error - serviceConfig.HealthChecks.Liveness, err = parseHealthCheck(*composeServiceConfig.HealthCheck, *&composeServiceConfig.Labels) - if err != nil { - return kobject.KomposeObject{}, errors.Wrap(err, "Unable to parse health check") - } - } - - // HealthCheck Readiness - var readiness, errReadiness = parseHealthCheckReadiness(*&composeServiceConfig.Labels) - if !readiness.Disable { - serviceConfig.HealthChecks.Readiness = readiness - if errReadiness != nil { - return kobject.KomposeObject{}, errors.Wrap(errReadiness, "Unable to parse health check") - } - } - - // restart-policy: deploy.restart_policy.condition will rewrite restart option - // see: https://docs.docker.com/compose/compose-file/#restart_policy - serviceConfig.Restart = composeServiceConfig.Restart - if composeServiceConfig.Deploy.RestartPolicy != nil { - serviceConfig.Restart = composeServiceConfig.Deploy.RestartPolicy.Condition - } - if serviceConfig.Restart == "unless-stopped" { - log.Warnf("Restart policy 'unless-stopped' in service %s is not supported, convert it to 'always'", name) - serviceConfig.Restart = "always" - } - - // replicas: - if composeServiceConfig.Deploy.Replicas != nil { - serviceConfig.Replicas = int(*composeServiceConfig.Deploy.Replicas) - } - - // placement: - serviceConfig.Placement = loadV3Placement(composeServiceConfig.Deploy.Placement) - - if composeServiceConfig.Deploy.UpdateConfig != nil { - serviceConfig.DeployUpdateConfig = *composeServiceConfig.Deploy.UpdateConfig - } - - // TODO: Build is not yet supported, see: - // https://github.com/docker/cli/blob/master/cli/compose/types/types.go#L9 - // We will have to *manually* add this / parse. - serviceConfig.Build = resolveV3Context(composeObject.Filename, composeServiceConfig.Build.Context) - serviceConfig.Dockerfile = composeServiceConfig.Build.Dockerfile - serviceConfig.BuildArgs = composeServiceConfig.Build.Args - serviceConfig.BuildLabels = composeServiceConfig.Build.Labels - - // env - parseV3Environment(&composeServiceConfig, &serviceConfig) - - // Get env_file - serviceConfig.EnvFile = composeServiceConfig.EnvFile - - // Parse the ports - // v3 uses a new format called "long syntax" starting in 3.2 - // https://docs.docker.com/compose/compose-file/#ports - - // here we will translate `expose` too, they basically means the same thing in kubernetes - serviceConfig.Port = loadV3Ports(composeServiceConfig.Ports, serviceConfig.Expose) - - // Parse the volumes - // Again, in v3, we use the "long syntax" for volumes in terms of parsing - // https://docs.docker.com/compose/compose-file/#long-syntax-3 - serviceConfig.VolList = loadV3Volumes(composeServiceConfig.Volumes) - if err := parseKomposeLabels(composeServiceConfig.Labels, &serviceConfig); err != nil { - return kobject.KomposeObject{}, err - } - - // Log if the name will been changed - if normalizeServiceNames(name) != name { - log.Infof("Service name in docker-compose has been changed from %q to %q", name, normalizeServiceNames(name)) - } - - serviceConfig.Configs = composeServiceConfig.Configs - serviceConfig.ConfigsMetaData = composeObject.Configs - if composeServiceConfig.Deploy.EndpointMode == "vip" { - serviceConfig.ServiceType = string(api.ServiceTypeNodePort) - } - // Final step, add to the array! - komposeObject.ServiceConfigs[normalizeServiceNames(name)] = serviceConfig - } - - handleV3Volume(&komposeObject, &composeObject.Volumes) - return komposeObject, nil -} - -// resolveV3Context resolves build context like v2 does, see: -// https://github.com/docker/libcompose/blob/master/config/merge_v2.go#L155 -func resolveV3Context(inFile string, context string) string { - if context == "" { - return "" - } - - current := path.Dir(inFile) - if context != "." { - current = path.Join(current, context) - } - - return current -} - -func parseV3Network(composeServiceConfig *types.ServiceConfig, serviceConfig *kobject.ServiceConfig, composeObject *types.Config) error { - if len(composeServiceConfig.Networks) == 0 { - if defaultNetwork, ok := composeObject.Networks["default"]; ok { - normalizedNetworkName, err := normalizeNetworkNames(defaultNetwork.Name) - if err != nil { - return errors.Wrap(err, "Unable to normalize network name") - } - serviceConfig.Network = append(serviceConfig.Network, normalizedNetworkName) - } - } else { - var alias = "" - for key := range composeServiceConfig.Networks { - alias = key - netName := composeObject.Networks[alias].Name - - // if Network Name Field is empty in the docker-compose definition - // we will use the alias name defined in service config file - if netName == "" { - netName = alias - } - - normalizedNetworkName, err := normalizeNetworkNames(netName) - if err != nil { - return errors.Wrap(err, "Unable to normalize network name") - } - - serviceConfig.Network = append(serviceConfig.Network, normalizedNetworkName) - } - } - - return nil -} - -func parseV3Resources(composeServiceConfig *types.ServiceConfig, serviceConfig *kobject.ServiceConfig) error { - if (composeServiceConfig.Deploy.Resources != types.Resources{}) { - // memory: - // TODO: Refactor yaml.MemStringorInt in kobject.go to int64 - // cpu: - // convert to k8s format, for example: 0.5 = 500m - // See: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - // "The expression 0.1 is equivalent to the expression 100m, which can be read as “one hundred millicpu”." - - // Since Deploy.Resources.Limits does not initialize, we must check type Resources before continuing - if composeServiceConfig.Deploy.Resources.Limits != nil { - serviceConfig.MemLimit = libcomposeyaml.MemStringorInt(composeServiceConfig.Deploy.Resources.Limits.MemoryBytes) - - if composeServiceConfig.Deploy.Resources.Limits.NanoCPUs != "" { - cpuLimit, err := strconv.ParseFloat(composeServiceConfig.Deploy.Resources.Limits.NanoCPUs, 64) - if err != nil { - return errors.Wrap(err, "Unable to convert cpu limits resources value") - } - serviceConfig.CPULimit = int64(cpuLimit * 1000) - } - } - if composeServiceConfig.Deploy.Resources.Reservations != nil { - serviceConfig.MemReservation = libcomposeyaml.MemStringorInt(composeServiceConfig.Deploy.Resources.Reservations.MemoryBytes) - - if composeServiceConfig.Deploy.Resources.Reservations.NanoCPUs != "" { - cpuReservation, err := strconv.ParseFloat(composeServiceConfig.Deploy.Resources.Reservations.NanoCPUs, 64) - if err != nil { - return errors.Wrap(err, "Unable to convert cpu limits reservation value") - } - serviceConfig.CPUReservation = int64(cpuReservation * 1000) - } - } - } - return nil -} - -func parseV3Environment(composeServiceConfig *types.ServiceConfig, serviceConfig *kobject.ServiceConfig) { - // Gather the environment values - // DockerCompose uses map[string]*string while we use []string - // So let's convert that using this hack - // Note: unset env pick up the env value on host if exist - for name, value := range composeServiceConfig.Environment { - var env kobject.EnvVar - if value != nil { - env = kobject.EnvVar{Name: name, Value: *value} - } else { - result, ok := os.LookupEnv(name) - if ok { - env = kobject.EnvVar{Name: name, Value: result} - } else { - continue - } - } - serviceConfig.Environment = append(serviceConfig.Environment, env) - } -} - -// parseKomposeLabels parse kompose labels, also do some validation -func parseKomposeLabels(labels map[string]string, serviceConfig *kobject.ServiceConfig) error { - // Label handler - // Labels used to influence conversion of kompose will be handled - // from here for docker-compose. Each loader will have such handler. - if serviceConfig.Labels == nil { - serviceConfig.Labels = make(map[string]string) - } - - for key, value := range labels { - switch key { - case LabelServiceType: - serviceType, err := handleServiceType(value) - if err != nil { - return errors.Wrap(err, "handleServiceType failed") - } - - serviceConfig.ServiceType = serviceType - case LabelServiceExpose: - serviceConfig.ExposeService = strings.Trim(strings.ToLower(value), " ,") - case LabelNodePortPort: - serviceConfig.NodePortPort = cast.ToInt32(value) - case LabelServiceExposeTLSSecret: - serviceConfig.ExposeServiceTLS = value - case LabelServiceExposeIngressClassName: - serviceConfig.ExposeServiceIngressClassName = value - case LabelImagePullSecret: - serviceConfig.ImagePullSecret = value - case LabelImagePullPolicy: - serviceConfig.ImagePullPolicy = value - default: - serviceConfig.Labels[key] = value - } - } - - if serviceConfig.ExposeService == "" && serviceConfig.ExposeServiceTLS != "" { - return errors.New("kompose.service.expose.tls-secret was specified without kompose.service.expose") - } - - if serviceConfig.ExposeService == "" && serviceConfig.ExposeServiceIngressClassName != "" { - return errors.New("kompose.service.expose.ingress-class-name was specified without kompose.service.expose") - } - - if serviceConfig.ServiceType != string(api.ServiceTypeNodePort) && serviceConfig.NodePortPort != 0 { - return errors.New("kompose.service.type must be nodeport when assign node port value") - } - - if len(serviceConfig.Port) > 1 && serviceConfig.NodePortPort != 0 { - return errors.New("cannot set kompose.service.nodeport.port when service has multiple ports") - } - - return nil -} - -func handleV3Volume(komposeObject *kobject.KomposeObject, volumes *map[string]types.VolumeConfig) { - for name := range komposeObject.ServiceConfigs { - // retrieve volumes of service - vols, err := retrieveVolume(name, *komposeObject) - if err != nil { - errors.Wrap(err, "could not retrieve vvolume") - } - for volName, vol := range vols { - size, selector := getV3VolumeLabels(vol.VolumeName, volumes) - if len(size) > 0 || len(selector) > 0 { - // We can't assign value to struct field in map while iterating over it, so temporary variable `temp` is used here - var temp = vols[volName] - temp.PVCSize = size - temp.SelectorValue = selector - vols[volName] = temp - } - } - // We can't assign value to struct field in map while iterating over it, so temporary variable `temp` is used here - var temp = komposeObject.ServiceConfigs[name] - temp.Volumes = vols - komposeObject.ServiceConfigs[name] = temp - } -} - -func getV3VolumeLabels(name string, volumes *map[string]types.VolumeConfig) (string, string) { - size, selector := "", "" - - if volume, ok := (*volumes)[name]; ok { - for key, value := range volume.Labels { - if key == "kompose.volume.size" { - size = value - } else if key == "kompose.volume.selector" { - selector = value - } - } - } - - return size, selector -} - -func mergeComposeObject(oldCompose *types.Config, newCompose *types.Config) (*types.Config, error) { - if oldCompose == nil || newCompose == nil { - return nil, fmt.Errorf("merge multiple compose error, compose config is nil") - } - oldComposeServiceNameMap := make(map[string]int, len(oldCompose.Services)) - for index, service := range oldCompose.Services { - oldComposeServiceNameMap[service.Name] = index - } - - for _, service := range newCompose.Services { - index := 0 - if tmpIndex, ok := oldComposeServiceNameMap[service.Name]; !ok { - oldCompose.Services = append(oldCompose.Services, service) - continue - } else { - index = tmpIndex - } - tmpOldService := oldCompose.Services[index] - if service.Build.Dockerfile != "" { - tmpOldService.Build = service.Build - } - if len(service.CapAdd) != 0 { - tmpOldService.CapAdd = service.CapAdd - } - if len(service.CapDrop) != 0 { - tmpOldService.CapDrop = service.CapDrop - } - if service.CgroupParent != "" { - tmpOldService.CgroupParent = service.CgroupParent - } - if len(service.Command) != 0 { - tmpOldService.Command = service.Command - } - if len(service.Configs) != 0 { - tmpOldService.Configs = service.Configs - } - if service.ContainerName != "" { - tmpOldService.ContainerName = service.ContainerName - } - if service.CredentialSpec.File != "" || service.CredentialSpec.Registry != "" { - tmpOldService.CredentialSpec = service.CredentialSpec - } - if len(service.DependsOn) != 0 { - tmpOldService.DependsOn = service.DependsOn - } - if service.Deploy.Mode != "" { - tmpOldService.Deploy = service.Deploy - } - if service.Deploy.Resources.Limits != nil { - tmpOldService.Deploy.Resources.Limits = service.Deploy.Resources.Limits - } - - if service.Deploy.Resources.Reservations != nil { - tmpOldService.Deploy.Resources.Reservations = service.Deploy.Resources.Reservations - } - if service.Deploy.Replicas != nil { - tmpOldService.Deploy.Replicas = service.Deploy.Replicas - } - - if len(service.Devices) != 0 { - // merge the 2 sets of values - // TODO: need to merge the sets based on target values - // Not implemented yet as we don't convert devices to k8s anyway - tmpOldService.Devices = service.Devices - } - - if len(service.DNS) != 0 { - // concat the 2 sets of values - tmpOldService.DNS = append(tmpOldService.DNS, service.DNS...) - } - if len(service.DNSSearch) != 0 { - // concat the 2 sets of values - tmpOldService.DNSSearch = append(tmpOldService.DNSSearch, service.DNSSearch...) - } - if service.DomainName != "" { - tmpOldService.DomainName = service.DomainName - } - if len(service.Entrypoint) != 0 { - tmpOldService.Entrypoint = service.Entrypoint - } - if len(service.Environment) != 0 { - // merge the 2 sets of values - for k, v := range service.Environment { - tmpOldService.Environment[k] = v - } - } - if len(service.EnvFile) != 0 { - tmpOldService.EnvFile = service.EnvFile - } - if len(service.Expose) != 0 { - // concat the 2 sets of values - tmpOldService.Expose = append(tmpOldService.Expose, service.Expose...) - } - if len(service.ExternalLinks) != 0 { - // concat the 2 sets of values - tmpOldService.ExternalLinks = append(tmpOldService.ExternalLinks, service.ExternalLinks...) - } - if len(service.ExtraHosts) != 0 { - tmpOldService.ExtraHosts = service.ExtraHosts - } - if service.Hostname != "" { - tmpOldService.Hostname = service.Hostname - } - if service.HealthCheck != nil { - tmpOldService.HealthCheck = service.HealthCheck - } - if service.Image != "" { - tmpOldService.Image = service.Image - } - - if service.Ipc != "" { - tmpOldService.Ipc = service.Ipc - } - if len(service.Labels) != 0 { - // merge the 2 sets of values - if tmpOldService.Labels == nil { - tmpOldService.Labels = make(map[string]string) - } - for k, v := range service.Labels { - tmpOldService.Labels[k] = v - } - } - if len(service.Links) != 0 { - tmpOldService.Links = service.Links - } - if service.Logging != nil { - tmpOldService.Logging = service.Logging - } - if service.MacAddress != "" { - tmpOldService.MacAddress = service.MacAddress - } - if service.NetworkMode != "" { - tmpOldService.NetworkMode = service.NetworkMode - } - if len(service.Networks) != 0 { - tmpOldService.Networks = service.Networks - } - if service.Pid != "" { - tmpOldService.Pid = service.Pid - } - if len(service.Ports) != 0 { - // concat the 2 sets of values - tmpOldService.Ports = append(tmpOldService.Ports, service.Ports...) - } - if service.Privileged != tmpOldService.Privileged { - tmpOldService.Privileged = service.Privileged - } - if service.ReadOnly != tmpOldService.ReadOnly { - tmpOldService.ReadOnly = service.ReadOnly - } - if service.Restart != "" { - tmpOldService.Restart = service.Restart - } - if len(service.Secrets) != 0 { - tmpOldService.Secrets = service.Secrets - } - if len(service.SecurityOpt) != 0 { - tmpOldService.SecurityOpt = service.SecurityOpt - } - if service.StdinOpen != tmpOldService.StdinOpen { - tmpOldService.StdinOpen = service.StdinOpen - } - if service.StopSignal != "" { - tmpOldService.StopSignal = service.StopSignal - } - if len(service.Tmpfs) != 0 { - // concat the 2 sets of values - tmpOldService.Tmpfs = append(tmpOldService.Tmpfs, service.Tmpfs...) - } - if service.Tty != tmpOldService.Tty { - tmpOldService.Tty = service.Tty - } - if len(service.Ulimits) != 0 { - tmpOldService.Ulimits = service.Ulimits - } - if service.User != "" { - tmpOldService.User = service.User - } - if len(service.Volumes) != 0 { - // merge the 2 sets of values - - // Store volumes by Target - volumeConfigsMap := make(map[string]types.ServiceVolumeConfig) - // map is not iterated in the same order. - // but why only this code cause test error? - var keys []string - - // populate the older values - for _, volConfig := range tmpOldService.Volumes { - volumeConfigsMap[volConfig.Target] = volConfig - keys = append(keys, volConfig.Target) - } - // add the new values, overriding as needed - for _, volConfig := range service.Volumes { - if _, ok := volumeConfigsMap[volConfig.Target]; !ok { - keys = append(keys, volConfig.Target) - } - volumeConfigsMap[volConfig.Target] = volConfig - } - - // get the new list of volume configs - var volumes []types.ServiceVolumeConfig - - for _, key := range keys { - volumes = append(volumes, volumeConfigsMap[key]) - } - - tmpOldService.Volumes = volumes - } - if service.WorkingDir != "" { - tmpOldService.WorkingDir = service.WorkingDir - } - oldCompose.Services[index] = tmpOldService - } - - // Merge the networks information - for idx, network := range newCompose.Networks { - oldCompose.Networks[idx] = network - } - - // Merge the volumes information - for idx, volume := range newCompose.Volumes { - oldCompose.Volumes[idx] = volume - } - - // Merge the secrets information - for idx, secret := range newCompose.Secrets { - oldCompose.Secrets[idx] = secret - } - - // Merge the configs information - for idx, config := range newCompose.Configs { - oldCompose.Configs[idx] = config - } - - return oldCompose, nil -} - -func checkUnsupportedKeyForV3(composeObject *types.Config) []string { - if composeObject == nil { - return []string{} - } - - var keysFound []string - - for _, service := range composeObject.Services { - for _, tmpConfig := range service.Configs { - if tmpConfig.GID != "" { - keysFound = append(keysFound, "long syntax config gid") - } - if tmpConfig.UID != "" { - keysFound = append(keysFound, "long syntax config uid") - } - } - - if service.CredentialSpec.Registry != "" || service.CredentialSpec.File != "" { - keysFound = append(keysFound, "credential_spec") - } - } - - for _, config := range composeObject.Configs { - if config.External.External { - keysFound = append(keysFound, "external config") - } - } - - return keysFound -} diff --git a/pkg/transformer/kubernetes/k8sutils.go b/pkg/transformer/kubernetes/k8sutils.go index 0ab048ee..4f5c72dd 100644 --- a/pkg/transformer/kubernetes/k8sutils.go +++ b/pkg/transformer/kubernetes/k8sutils.go @@ -493,10 +493,8 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic } } - if cms != nil { - for _, c := range cms { - *objects = append(*objects, c) - } + for _, c := range cms { + *objects = append(*objects, c) } // Configure the container ports. @@ -724,8 +722,6 @@ func TranslatePodResource(service *kobject.ServiceConfig, template *api.PodTempl template.Spec.Containers[0].Resources.Requests = resourceRequests } - - return } // GetImagePullPolicy get image pull settings diff --git a/pkg/transformer/kubernetes/k8sutils_test.go b/pkg/transformer/kubernetes/k8sutils_test.go index e9358905..410e666f 100644 --- a/pkg/transformer/kubernetes/k8sutils_test.go +++ b/pkg/transformer/kubernetes/k8sutils_test.go @@ -39,8 +39,8 @@ func TestCreateService(t *testing.T) { service := kobject.ServiceConfig{ ContainerName: "name", Image: "image", - Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, - Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, Command: []string{"cmd"}, WorkingDir: "dir", Args: []string{"arg1", "arg2"}, @@ -82,8 +82,8 @@ func TestCreateServiceWithMemLimit(t *testing.T) { service := kobject.ServiceConfig{ ContainerName: "name", Image: "image", - Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, - Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, Command: []string{"cmd"}, WorkingDir: "dir", Args: []string{"arg1", "arg2"}, @@ -134,8 +134,8 @@ func TestCreateServiceWithCPULimit(t *testing.T) { service := kobject.ServiceConfig{ ContainerName: "name", Image: "image", - Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, - Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, Command: []string{"cmd"}, WorkingDir: "dir", Args: []string{"arg1", "arg2"}, @@ -187,8 +187,8 @@ func TestCreateServiceWithServiceUser(t *testing.T) { service := kobject.ServiceConfig{ ContainerName: "name", Image: "image", - Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, - Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, Command: []string{"cmd"}, WorkingDir: "dir", Args: []string{"arg1", "arg2"}, @@ -230,8 +230,8 @@ func TestTransformWithPid(t *testing.T) { service := kobject.ServiceConfig{ ContainerName: "name", Image: "image", - Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, - Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, Command: []string{"cmd"}, WorkingDir: "dir", Args: []string{"arg1", "arg2"}, @@ -266,8 +266,8 @@ func TestTransformWithInvalidPid(t *testing.T) { service := kobject.ServiceConfig{ ContainerName: "name", Image: "image", - Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, - Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, Command: []string{"cmd"}, WorkingDir: "dir", Args: []string{"arg1", "arg2"}, diff --git a/pkg/transformer/kubernetes/kubernetes.go b/pkg/transformer/kubernetes/kubernetes.go index 7cf70f74..500d31d3 100644 --- a/pkg/transformer/kubernetes/kubernetes.go +++ b/pkg/transformer/kubernetes/kubernetes.go @@ -29,7 +29,7 @@ import ( "strconv" "strings" - "github.com/docker/cli/cli/compose/types" + "github.com/compose-spec/compose-go/types" "github.com/fatih/structs" "github.com/kubernetes/kompose/pkg/kobject" "github.com/kubernetes/kompose/pkg/loader/compose" @@ -871,7 +871,7 @@ func (k *Kubernetes) getSecretPathsLegacy(secretConfig types.ServiceSecretConfig } // if the target isn't absolute path - if strings.HasPrefix(secretConfig.Target, "/") == false { + if !strings.HasPrefix(secretConfig.Target, "/") { // concat the default secret directory mountPath = "/run/secrets/" + mountPath } @@ -1474,20 +1474,17 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject. SetVolumes(volumes), ) - if pvc != nil { - // Looping on the slice pvc instead of `*objects = append(*objects, pvc...)` - // because the type of objects and pvc is different, but when doing append - // one element at a time it gets converted to runtime.Object for objects slice - for _, p := range pvc { - objects = append(objects, p) - } + // Looping on the slice pvc instead of `*objects = append(*objects, pvc...)` + // because the type of objects and pvc is different, but when doing append + // one element at a time it gets converted to runtime.Object for objects slice + for _, p := range pvc { + objects = append(objects, p) } - if cms != nil { - for _, c := range cms { - objects = append(objects, c) - } + for _, c := range cms { + objects = append(objects, c) } + podSpec.Append( SetPorts(service), ImagePullPolicy(name, service), diff --git a/pkg/transformer/kubernetes/kubernetes_test.go b/pkg/transformer/kubernetes/kubernetes_test.go index dad1488f..0973c91a 100644 --- a/pkg/transformer/kubernetes/kubernetes_test.go +++ b/pkg/transformer/kubernetes/kubernetes_test.go @@ -23,7 +23,7 @@ import ( "strings" "testing" - dockerCliTypes "github.com/docker/cli/cli/compose/types" + "github.com/compose-spec/compose-go/types" "github.com/kubernetes/kompose/pkg/kobject" "github.com/kubernetes/kompose/pkg/loader/compose" @@ -43,8 +43,8 @@ func newServiceConfig() kobject.ServiceConfig { Name: "app", ContainerName: "name", Image: "image", - Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, - Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456}, kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: string(api.ProtocolUDP)}, kobject.Ports{HostPort: 55564, ContainerPort: 55564}, kobject.Ports{HostPort: 55563, ContainerPort: 55563}}, + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456}, {HostPort: 123, ContainerPort: 456, Protocol: string(api.ProtocolUDP)}, {HostPort: 55564, ContainerPort: 55564}, {HostPort: 55563, ContainerPort: 55563}}, Command: []string{"cmd"}, WorkingDir: "dir", Args: []string{"arg1", "arg2"}, @@ -65,8 +65,8 @@ func newServiceConfig() kobject.ServiceConfig { Replicas: 2, Volumes: []kobject.Volumes{{SvcName: "app", MountPath: "/tmp/volume", PVCName: "app-claim0"}}, GroupAdd: []int64{1003, 1005}, - Configs: []dockerCliTypes.ServiceConfigObjConfig{{Source: "config", Target: "/etc/world"}}, - ConfigsMetaData: map[string]dockerCliTypes.ConfigObjConfig{"config": dockerCliTypes.ConfigObjConfig{Name: "myconfig", File: "kubernetes_test.go"}}, + Configs: []types.ServiceConfigObjConfig{{Source: "config", Target: "/etc/world"}}, + ConfigsMetaData: types.Configs{"config": types.ConfigObjConfig{Name: "myconfig", File: "kubernetes_test.go"}}, } } @@ -495,7 +495,7 @@ func TestKomposeConvert(t *testing.T) { if (int)(dc.Spec.Replicas) != replicas { t.Errorf("Expected %d replicas, got %d", replicas, dc.Spec.Replicas) } - if len(dc.Spec.Selector) < 0 { + if len(dc.Spec.Selector) == 0 { t.Errorf("Expect selector be set, got: %#v", dc.Spec.Selector) } foundDC = true @@ -529,8 +529,8 @@ func TestConvertRestartOptions(t *testing.T) { svc kobject.KomposeObject restartPolicy api.RestartPolicy }{ - "'restart' is set to 'no'": {kobject.KomposeObject{ServiceConfigs: map[string]kobject.ServiceConfig{"app": kobject.ServiceConfig{Image: "foobar", Restart: "no"}}}, api.RestartPolicyNever}, - "'restart' is set to 'on-failure'": {kobject.KomposeObject{ServiceConfigs: map[string]kobject.ServiceConfig{"app": kobject.ServiceConfig{Image: "foobar", Restart: "on-failure"}}}, api.RestartPolicyOnFailure}, + "'restart' is set to 'no'": {kobject.KomposeObject{ServiceConfigs: map[string]kobject.ServiceConfig{"app": {Image: "foobar", Restart: "no"}}}, api.RestartPolicyNever}, + "'restart' is set to 'on-failure'": {kobject.KomposeObject{ServiceConfigs: map[string]kobject.ServiceConfig{"app": {Image: "foobar", Restart: "on-failure"}}}, api.RestartPolicyOnFailure}, } for name, test := range testCases { diff --git a/pkg/transformer/openshift/openshift.go b/pkg/transformer/openshift/openshift.go index f47d33c5..86e094bb 100644 --- a/pkg/transformer/openshift/openshift.go +++ b/pkg/transformer/openshift/openshift.go @@ -190,10 +190,10 @@ func (o *OpenShift) initDeploymentConfig(name string, service kobject.ServiceCon }, Triggers: []deployapi.DeploymentTriggerPolicy{ // Trigger new deploy when DeploymentConfig is created (config change) - deployapi.DeploymentTriggerPolicy{ + { Type: deployapi.DeploymentTriggerOnConfigChange, }, - deployapi.DeploymentTriggerPolicy{ + { Type: deployapi.DeploymentTriggerOnImageChange, ImageChangeParams: &deployapi.DeploymentTriggerImageChangeParams{ //Automatic - if new tag is detected - update image update inside the pod template diff --git a/pkg/transformer/openshift/openshift_test.go b/pkg/transformer/openshift/openshift_test.go index 2bd3a061..9af2dbb2 100644 --- a/pkg/transformer/openshift/openshift_test.go +++ b/pkg/transformer/openshift/openshift_test.go @@ -36,8 +36,8 @@ func newServiceConfig() kobject.ServiceConfig { return kobject.ServiceConfig{ ContainerName: "myfoobarname", Image: "image", - Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, - Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, + Environment: []kobject.EnvVar{{Name: "env", Value: "value"}}, + Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}}, Command: []string{"cmd"}, WorkingDir: "dir", Args: []string{"arg1", "arg2"}, @@ -125,7 +125,7 @@ func TestKomposeConvertRoute(t *testing.T) { } } -//Test getting git remote url for a directory +// Test getting git remote url for a directory func TestGetGitRemote(t *testing.T) { var output string var err error diff --git a/pkg/transformer/utils.go b/pkg/transformer/utils.go index ae464fdc..dd270d30 100644 --- a/pkg/transformer/utils.go +++ b/pkg/transformer/utils.go @@ -342,7 +342,7 @@ func GetComposeFileDir(inputFiles []string) (string, error) { return filepath.Dir(inputFile), nil } -//BuildDockerImage builds docker image +// BuildDockerImage builds docker image func BuildDockerImage(service kobject.ServiceConfig, name string) error { wd, err := os.Getwd() if err != nil { diff --git a/pkg/transformer/utils_test.go b/pkg/transformer/utils_test.go index 5c232719..cc0d2cf5 100644 --- a/pkg/transformer/utils_test.go +++ b/pkg/transformer/utils_test.go @@ -119,7 +119,7 @@ func TestParseWindowsVolumeMountLinuxContainer(t *testing.T) { }, { "container", - fmt.Sprintf("%s", linuxContainer), + linuxContainer, "", "", linuxContainer, @@ -214,7 +214,7 @@ func TestParseWindowsVolumeMountWindowsContainer(t *testing.T) { }, { "container", - fmt.Sprintf("%s", windowsContainer), + windowsContainer, "", "", windowsContainer, @@ -311,7 +311,7 @@ func TestParseVolume(t *testing.T) { }, { "container", - fmt.Sprintf("%s", container2), + container2, "", "", container2, diff --git a/pkg/utils/docker/push.go b/pkg/utils/docker/push.go index bd07b9b3..14296182 100644 --- a/pkg/utils/docker/push.go +++ b/pkg/utils/docker/push.go @@ -82,9 +82,10 @@ func (c *Push) PushImage(image Image) error { // handleDockerRegistry adapt legacy docker registry address // After docker login to docker.io, there must be https://index.docker.io/v1/ in config.json of authentication // Reference: https://docs.docker.com/engine/api/v1.23/ -// > However (for legacy reasons) the “official” Docker, Inc. hosted registry -// > must be specified with both a “https://” prefix and a “/v1/” suffix -// > even though Docker will prefer to use the v2 registry API. +// +// > However (for legacy reasons) the “official” Docker, Inc. hosted registry +// > must be specified with both a “https://” prefix and a “/v1/” suffix +// > even though Docker will prefer to use the v2 registry API. func handleDockerRegistry(auth *dockerlib.AuthConfigurations) { const address = "docker.io" const legacyAddress = "https://index.docker.io/v1/" diff --git a/script/test/cmd/tests_new.sh b/script/test/cmd/tests_new.sh index 2cb5836a..92c21008 100755 --- a/script/test/cmd/tests_new.sh +++ b/script/test/cmd/tests_new.sh @@ -148,7 +148,7 @@ k8s_output="$KOMPOSE_ROOT/script/test/fixtures/change-in-volume/output-k8s-empty os_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/change-in-volume/docker-compose.yml convert --with-kompose-annotation=false --stdout --volumes emptyDir" os_output="$KOMPOSE_ROOT/script/test/fixtures/change-in-volume/output-os-empty-vols-template.yaml" convert::expect_success_and_warning "$k8s_cmd" "$k8s_output" -convert::expect_success_and_warning "$os_cmd" "$os_output" +convert::expect_success "$os_cmd" "$os_output" # Test that emptyvols works k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/change-in-volume/docker-compose.yml convert --with-kompose-annotation=false --stdout --emptyvols" @@ -163,7 +163,7 @@ k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/expose/compose.yaml conve ocp_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/expose/compose.yaml convert --stdout --with-kompose-annotation=false" k8s_output="$KOMPOSE_ROOT/script/test/fixtures/expose/output-k8s.yaml" ocp_output="$KOMPOSE_ROOT/script/test/fixtures/expose/output-os.yaml" -convert::expect_success "$k8s_cmd" "$k8s_output" +convert::expect_success_and_warning "$k8s_cmd" "$k8s_output" convert::expect_success "$ocp_cmd" "$ocp_output" @@ -193,7 +193,7 @@ k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/statefulset/docker-compos ocp_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/statefulset/docker-compose.yaml convert --stdout --with-kompose-annotation=false --controller statefulset" k8s_output="$KOMPOSE_ROOT/script/test/fixtures/statefulset/output-k8s.yaml" ocp_output="$KOMPOSE_ROOT/script/test/fixtures/statefulset/output-os.yaml" -convert::expect_success "$k8s_cmd" "$k8s_output" +convert::expect_success_and_warning "$k8s_cmd" "$k8s_output" convert::expect_success "$ocp_cmd" "$ocp_output" # test specifying volume type using service label diff --git a/script/test/fixtures/change-in-volume/output-k8s-empty-vols-template.yaml b/script/test/fixtures/change-in-volume/output-k8s-empty-vols-template.yaml index acc86e97..905b4d8e 100644 --- a/script/test/fixtures/change-in-volume/output-k8s-empty-vols-template.yaml +++ b/script/test/fixtures/change-in-volume/output-k8s-empty-vols-template.yaml @@ -59,6 +59,7 @@ spec: kompose.service.type: headless creationTimestamp: null labels: + io.kompose.network/change-in-volume-default: "true" io.kompose.service: redis spec: containers: @@ -68,6 +69,22 @@ spec: restartPolicy: Always status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: change-in-volume-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/change-in-volume-default: "true" + podSelector: + matchLabels: + io.kompose.network/change-in-volume-default: "true" + --- apiVersion: apps/v1 kind: Deployment @@ -87,6 +104,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/change-in-volume-default: "true" io.kompose.service: web spec: containers: @@ -106,3 +124,4 @@ spec: - emptyDir: {} name: code-volume status: {} + diff --git a/script/test/fixtures/change-in-volume/output-k8s.yaml b/script/test/fixtures/change-in-volume/output-k8s.yaml index f885f0e8..905b4d8e 100644 --- a/script/test/fixtures/change-in-volume/output-k8s.yaml +++ b/script/test/fixtures/change-in-volume/output-k8s.yaml @@ -59,6 +59,7 @@ spec: kompose.service.type: headless creationTimestamp: null labels: + io.kompose.network/change-in-volume-default: "true" io.kompose.service: redis spec: containers: @@ -68,6 +69,22 @@ spec: restartPolicy: Always status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: change-in-volume-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/change-in-volume-default: "true" + podSelector: + matchLabels: + io.kompose.network/change-in-volume-default: "true" + --- apiVersion: apps/v1 kind: Deployment @@ -87,6 +104,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/change-in-volume-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/change-in-volume/output-os-empty-vols-template.yaml b/script/test/fixtures/change-in-volume/output-os-empty-vols-template.yaml index 12abf953..142fabe2 100644 --- a/script/test/fixtures/change-in-volume/output-os-empty-vols-template.yaml +++ b/script/test/fixtures/change-in-volume/output-os-empty-vols-template.yaml @@ -57,6 +57,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/change-in-volume-default: "true" io.kompose.service: redis spec: containers: @@ -126,6 +127,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/change-in-volume-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/change-in-volume/output-os.yaml b/script/test/fixtures/change-in-volume/output-os.yaml index 12abf953..142fabe2 100644 --- a/script/test/fixtures/change-in-volume/output-os.yaml +++ b/script/test/fixtures/change-in-volume/output-os.yaml @@ -57,6 +57,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/change-in-volume-default: "true" io.kompose.service: redis spec: containers: @@ -126,6 +127,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/change-in-volume-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/configmap-volume/output-k8s-withlabel.yaml b/script/test/fixtures/configmap-volume/output-k8s-withlabel.yaml index 40020eba..d29f5373 100644 --- a/script/test/fixtures/configmap-volume/output-k8s-withlabel.yaml +++ b/script/test/fixtures/configmap-volume/output-k8s-withlabel.yaml @@ -21,6 +21,7 @@ spec: kompose.volume.type: configMap creationTimestamp: null labels: + io.kompose.network/configmap-volume-default: "true" io.kompose.service: db spec: containers: @@ -54,6 +55,22 @@ metadata: io.kompose.service: db name: db-cm0 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: configmap-volume-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/configmap-volume-default: "true" + podSelector: + matchLabels: + io.kompose.network/configmap-volume-default: "true" + --- apiVersion: apps/v1 kind: Deployment @@ -77,6 +94,7 @@ spec: kompose.volume.type: configMap creationTimestamp: null labels: + io.kompose.network/configmap-volume-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/configmap-volume/output-k8s.yaml b/script/test/fixtures/configmap-volume/output-k8s.yaml index f1fcae50..97be9ce9 100644 --- a/script/test/fixtures/configmap-volume/output-k8s.yaml +++ b/script/test/fixtures/configmap-volume/output-k8s.yaml @@ -17,6 +17,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/configmap-volume-default: "true" io.kompose.service: db spec: containers: @@ -50,6 +51,22 @@ metadata: io.kompose.service: db name: db-cm0 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: configmap-volume-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/configmap-volume-default: "true" + podSelector: + matchLabels: + io.kompose.network/configmap-volume-default: "true" + --- apiVersion: apps/v1 kind: Deployment @@ -69,6 +86,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/configmap-volume-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/configmap-volume/output-os-withlabel.yaml b/script/test/fixtures/configmap-volume/output-os-withlabel.yaml index 926211b8..b8752be8 100644 --- a/script/test/fixtures/configmap-volume/output-os-withlabel.yaml +++ b/script/test/fixtures/configmap-volume/output-os-withlabel.yaml @@ -19,6 +19,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/configmap-volume-default: "true" io.kompose.service: db spec: containers: @@ -114,6 +115,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/configmap-volume-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/configmap-volume/output-os.yaml b/script/test/fixtures/configmap-volume/output-os.yaml index 522894a8..92870173 100644 --- a/script/test/fixtures/configmap-volume/output-os.yaml +++ b/script/test/fixtures/configmap-volume/output-os.yaml @@ -17,6 +17,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/configmap-volume-default: "true" io.kompose.service: db spec: containers: @@ -110,6 +111,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/configmap-volume-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/deploy/placement/output-placement-k8s.yaml b/script/test/fixtures/deploy/placement/output-placement-k8s.yaml index cae39db4..777a2f0e 100644 --- a/script/test/fixtures/deploy/placement/output-placement-k8s.yaml +++ b/script/test/fixtures/deploy/placement/output-placement-k8s.yaml @@ -34,6 +34,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/placement-default: "true" io.kompose.service: redis spec: affinity: @@ -75,3 +76,19 @@ spec: whenUnsatisfiable: ScheduleAnyway status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: placement-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/placement-default: "true" + podSelector: + matchLabels: + io.kompose.network/placement-default: "true" + diff --git a/script/test/fixtures/deploy/placement/output-placement-os.yaml b/script/test/fixtures/deploy/placement/output-placement-os.yaml index 47ac9b4e..44583be4 100644 --- a/script/test/fixtures/deploy/placement/output-placement-os.yaml +++ b/script/test/fixtures/deploy/placement/output-placement-os.yaml @@ -34,6 +34,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/placement-default: "true" io.kompose.service: redis spec: affinity: diff --git a/script/test/fixtures/envvars-interpolation/output-k8s.yaml b/script/test/fixtures/envvars-interpolation/output-k8s.yaml index bacee721..e34faff0 100644 --- a/script/test/fixtures/envvars-interpolation/output-k8s.yaml +++ b/script/test/fixtures/envvars-interpolation/output-k8s.yaml @@ -16,6 +16,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/envvars-interpolation-default: "true" io.kompose.service: myservice spec: containers: @@ -33,3 +34,19 @@ spec: restartPolicy: Always status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: envvars-interpolation-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/envvars-interpolation-default: "true" + podSelector: + matchLabels: + io.kompose.network/envvars-interpolation-default: "true" + diff --git a/script/test/fixtures/envvars-interpolation/output-os.yaml b/script/test/fixtures/envvars-interpolation/output-os.yaml index f32ce7a1..15dac9a1 100644 --- a/script/test/fixtures/envvars-interpolation/output-os.yaml +++ b/script/test/fixtures/envvars-interpolation/output-os.yaml @@ -16,6 +16,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/envvars-interpolation-default: "true" io.kompose.service: myservice spec: containers: diff --git a/script/test/fixtures/expose/output-k8s.yaml b/script/test/fixtures/expose/output-k8s.yaml index 18f85905..4148a28f 100644 --- a/script/test/fixtures/expose/output-k8s.yaml +++ b/script/test/fixtures/expose/output-k8s.yaml @@ -56,6 +56,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/expose-default: "true" io.kompose.service: redis spec: containers: @@ -67,6 +68,22 @@ spec: restartPolicy: Always status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: expose-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/expose-default: "true" + podSelector: + matchLabels: + io.kompose.network/expose-default: "true" + --- apiVersion: apps/v1 kind: Deployment @@ -93,6 +110,7 @@ spec: kompose.service.expose.tls-secret: test-secret creationTimestamp: null labels: + io.kompose.network/expose-default: "true" io.kompose.service: web spec: containers: @@ -146,3 +164,4 @@ spec: secretName: test-secret status: loadBalancer: {} + diff --git a/script/test/fixtures/expose/output-os.yaml b/script/test/fixtures/expose/output-os.yaml index 8a089442..3a1f7aca 100644 --- a/script/test/fixtures/expose/output-os.yaml +++ b/script/test/fixtures/expose/output-os.yaml @@ -56,6 +56,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/expose-default: "true" io.kompose.service: redis spec: containers: @@ -130,6 +131,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/expose-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/healthcheck/output-healthcheck-k8s.yaml b/script/test/fixtures/healthcheck/output-healthcheck-k8s.yaml index f3f6cb8c..4acf7f6a 100644 --- a/script/test/fixtures/healthcheck/output-healthcheck-k8s.yaml +++ b/script/test/fixtures/healthcheck/output-healthcheck-k8s.yaml @@ -1,28 +1,3 @@ ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - kompose.service.group: my-group - kompose.service.healthcheck.liveness.tcp_port: "8080" - kompose.service.healthcheck.readiness.interval: 10s - kompose.service.healthcheck.readiness.retries: "5" - kompose.service.healthcheck.readiness.tcp_port: "9090" - kompose.service.healthcheck.readiness.timeout: 1s - creationTimestamp: null - labels: - io.kompose.service: my-group - name: mongo -spec: - ports: - - name: "27017" - port: 27017 - targetPort: 27017 - selector: - io.kompose.service: my-group -status: - loadBalancer: {} - --- apiVersion: v1 kind: Service @@ -48,6 +23,31 @@ spec: status: loadBalancer: {} +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.service.group: my-group + kompose.service.healthcheck.liveness.tcp_port: "8080" + kompose.service.healthcheck.readiness.interval: 10s + kompose.service.healthcheck.readiness.retries: "5" + kompose.service.healthcheck.readiness.tcp_port: "9090" + kompose.service.healthcheck.readiness.timeout: 1s + creationTimestamp: null + labels: + io.kompose.service: my-group + name: mongo +spec: + ports: + - name: "27017" + port: 27017 + targetPort: 27017 + selector: + io.kompose.service: my-group +status: + loadBalancer: {} + --- apiVersion: v1 kind: Service @@ -103,11 +103,11 @@ kind: Deployment metadata: annotations: kompose.service.group: my-group - kompose.service.healthcheck.liveness.tcp_port: "8081" - kompose.service.healthcheck.readiness.interval: 11s - kompose.service.healthcheck.readiness.retries: "6" - kompose.service.healthcheck.readiness.tcp_port: "9091" - kompose.service.healthcheck.readiness.timeout: 2s + kompose.service.healthcheck.liveness.tcp_port: "8080" + kompose.service.healthcheck.readiness.interval: 10s + kompose.service.healthcheck.readiness.retries: "5" + kompose.service.healthcheck.readiness.tcp_port: "9090" + kompose.service.healthcheck.readiness.timeout: 1s creationTimestamp: null labels: io.kompose.service: my-group @@ -122,33 +122,17 @@ spec: metadata: annotations: kompose.service.group: my-group - kompose.service.healthcheck.liveness.tcp_port: "8080" - kompose.service.healthcheck.readiness.interval: 10s - kompose.service.healthcheck.readiness.retries: "5" - kompose.service.healthcheck.readiness.tcp_port: "9090" - kompose.service.healthcheck.readiness.timeout: 1s + kompose.service.healthcheck.liveness.tcp_port: "8081" + kompose.service.healthcheck.readiness.interval: 11s + kompose.service.healthcheck.readiness.retries: "6" + kompose.service.healthcheck.readiness.tcp_port: "9091" + kompose.service.healthcheck.readiness.timeout: 2s creationTimestamp: null labels: + io.kompose.network/healthcheck-default: "true" io.kompose.service: my-group spec: containers: - - image: mongo - livenessProbe: - failureThreshold: 5 - periodSeconds: 10 - tcpSocket: - port: 8080 - timeoutSeconds: 1 - name: mongo - ports: - - containerPort: 27017 - readinessProbe: - failureThreshold: 5 - periodSeconds: 10 - tcpSocket: - port: 9090 - timeoutSeconds: 1 - resources: {} - image: mysql livenessProbe: failureThreshold: 6 @@ -166,9 +150,42 @@ spec: port: 9091 timeoutSeconds: 2 resources: {} + - image: mongo + livenessProbe: + failureThreshold: 5 + periodSeconds: 10 + tcpSocket: + port: 8080 + timeoutSeconds: 1 + name: mongo + ports: + - containerPort: 27017 + readinessProbe: + failureThreshold: 5 + periodSeconds: 10 + tcpSocket: + port: 9090 + timeoutSeconds: 1 + resources: {} restartPolicy: Always status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: healthcheck-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/healthcheck-default: "true" + podSelector: + matchLabels: + io.kompose.network/healthcheck-default: "true" + --- apiVersion: apps/v1 kind: Deployment @@ -203,6 +220,7 @@ spec: kompose.service.healthcheck.readiness.timeout: 1s creationTimestamp: null labels: + io.kompose.network/healthcheck-default: "true" io.kompose.service: postgresql spec: containers: @@ -256,6 +274,7 @@ spec: kompose.service.healthcheck.readiness.timeout: 1s creationTimestamp: null labels: + io.kompose.network/healthcheck-default: "true" io.kompose.service: redis spec: containers: diff --git a/script/test/fixtures/healthcheck/output-healthcheck-os.yaml b/script/test/fixtures/healthcheck/output-healthcheck-os.yaml index 1b4501fb..46e2f57b 100644 --- a/script/test/fixtures/healthcheck/output-healthcheck-os.yaml +++ b/script/test/fixtures/healthcheck/output-healthcheck-os.yaml @@ -122,6 +122,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/healthcheck-default: "true" io.kompose.service: mongo spec: containers: @@ -211,6 +212,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/healthcheck-default: "true" io.kompose.service: mysql spec: containers: @@ -301,6 +303,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/healthcheck-default: "true" io.kompose.service: postgresql spec: containers: @@ -390,6 +393,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/healthcheck-default: "true" io.kompose.service: redis spec: containers: diff --git a/script/test/fixtures/multiple-files/output-k8s.yaml b/script/test/fixtures/multiple-files/output-k8s.yaml index b45b2b07..8275916c 100644 --- a/script/test/fixtures/multiple-files/output-k8s.yaml +++ b/script/test/fixtures/multiple-files/output-k8s.yaml @@ -16,6 +16,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/multiple-files-default: "true" io.kompose.service: bar spec: containers: @@ -25,6 +26,22 @@ spec: restartPolicy: Always status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: multiple-files-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/multiple-files-default: "true" + podSelector: + matchLabels: + io.kompose.network/multiple-files-default: "true" + --- apiVersion: apps/v1 kind: Deployment @@ -43,6 +60,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/multiple-files-default: "true" io.kompose.service: foo spec: containers: @@ -51,3 +69,4 @@ spec: resources: {} restartPolicy: Always status: {} + diff --git a/script/test/fixtures/multiple-files/output-os.yaml b/script/test/fixtures/multiple-files/output-os.yaml index 00681afe..68cc31c4 100644 --- a/script/test/fixtures/multiple-files/output-os.yaml +++ b/script/test/fixtures/multiple-files/output-os.yaml @@ -16,6 +16,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/multiple-files-default: "true" io.kompose.service: bar spec: containers: @@ -84,6 +85,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/multiple-files-default: "true" io.kompose.service: foo spec: containers: diff --git a/script/test/fixtures/multiple-type-volumes/output-k8s.yaml b/script/test/fixtures/multiple-type-volumes/output-k8s.yaml index f6a47524..65877e89 100644 --- a/script/test/fixtures/multiple-type-volumes/output-k8s.yaml +++ b/script/test/fixtures/multiple-type-volumes/output-k8s.yaml @@ -21,6 +21,7 @@ spec: kompose.volume.type: persistentVolumeClaim creationTimestamp: null labels: + io.kompose.network/multiple-type-volumes-default: "true" io.kompose.service: db spec: containers: @@ -53,6 +54,22 @@ spec: storage: 100Mi status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: multiple-type-volumes-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/multiple-type-volumes-default: "true" + podSelector: + matchLabels: + io.kompose.network/multiple-type-volumes-default: "true" + --- apiVersion: apps/v1 kind: Deployment @@ -76,6 +93,7 @@ spec: kompose.volume.type: configMap creationTimestamp: null labels: + io.kompose.network/multiple-type-volumes-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/multiple-type-volumes/output-os.yaml b/script/test/fixtures/multiple-type-volumes/output-os.yaml index 7433f320..9ab5a4bd 100644 --- a/script/test/fixtures/multiple-type-volumes/output-os.yaml +++ b/script/test/fixtures/multiple-type-volumes/output-os.yaml @@ -19,6 +19,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/multiple-type-volumes-default: "true" io.kompose.service: db spec: containers: @@ -113,6 +114,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/multiple-type-volumes-default: "true" io.kompose.service: web spec: containers: diff --git a/script/test/fixtures/redis-example/docker-compose.yml b/script/test/fixtures/redis-example/docker-compose.yml index 42c1e9dd..e2ceb20c 100644 --- a/script/test/fixtures/redis-example/docker-compose.yml +++ b/script/test/fixtures/redis-example/docker-compose.yml @@ -1,10 +1,11 @@ -web: - image: tuna/docker-counter23 - ports: - - "5000:5000" - links: - - redis -redis: - image: redis:3.0 - ports: - - "6379" +services: + web: + image: tuna/docker-counter23 + ports: + - "5000:5000" + links: + - redis + redis: + image: redis:3.0 + ports: + - "6379" diff --git a/script/test/fixtures/service-group/output-k8s.yaml b/script/test/fixtures/service-group/output-k8s.yaml index 542df687..34fe6511 100644 --- a/script/test/fixtures/service-group/output-k8s.yaml +++ b/script/test/fixtures/service-group/output-k8s.yaml @@ -35,6 +35,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/service-group-default: "true" io.kompose.service: librenms-dispatcher spec: containers: @@ -82,3 +83,19 @@ spec: storage: 100Mi status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: service-group-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/service-group-default: "true" + podSelector: + matchLabels: + io.kompose.network/service-group-default: "true" + diff --git a/script/test/fixtures/single-file-output/output-k8s.yaml b/script/test/fixtures/single-file-output/output-k8s.yaml index da456831..370fd087 100644 --- a/script/test/fixtures/single-file-output/output-k8s.yaml +++ b/script/test/fixtures/single-file-output/output-k8s.yaml @@ -43,6 +43,7 @@ spec: kompose.service.expose.ingress-class-name: nginx creationTimestamp: null labels: + io.kompose.network/single-file-output-default: "true" io.kompose.service: front-end spec: containers: @@ -83,3 +84,20 @@ spec: pathType: Prefix status: loadBalancer: {} + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: single-file-output-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/single-file-output-default: "true" + podSelector: + matchLabels: + io.kompose.network/single-file-output-default: "true" + diff --git a/script/test/fixtures/statefulset/output-k8s.yaml b/script/test/fixtures/statefulset/output-k8s.yaml index 92506241..7985de88 100644 --- a/script/test/fixtures/statefulset/output-k8s.yaml +++ b/script/test/fixtures/statefulset/output-k8s.yaml @@ -56,6 +56,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/statefulset-default: "true" io.kompose.service: db spec: containers: @@ -94,6 +95,22 @@ spec: status: replicas: 0 +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: statefulset-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/statefulset-default: "true" + podSelector: + matchLabels: + io.kompose.network/statefulset-default: "true" + --- apiVersion: apps/v1 kind: StatefulSet @@ -112,6 +129,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/statefulset-default: "true" io.kompose.service: wordpress spec: containers: diff --git a/script/test/fixtures/statefulset/output-os.yaml b/script/test/fixtures/statefulset/output-os.yaml index 5e3a742a..2c9fbfd8 100644 --- a/script/test/fixtures/statefulset/output-os.yaml +++ b/script/test/fixtures/statefulset/output-os.yaml @@ -52,6 +52,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/statefulset-default: "true" io.kompose.service: db spec: containers: @@ -109,6 +110,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/statefulset-default: "true" io.kompose.service: db spec: containers: @@ -191,6 +193,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/statefulset-default: "true" io.kompose.service: wordpress spec: containers: @@ -248,6 +251,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/statefulset-default: "true" io.kompose.service: wordpress spec: containers: diff --git a/script/test/fixtures/v2/output-k8s.yaml b/script/test/fixtures/v2/output-k8s.yaml index e92a6965..48c69531 100644 --- a/script/test/fixtures/v2/output-k8s.yaml +++ b/script/test/fixtures/v2/output-k8s.yaml @@ -138,6 +138,7 @@ kind: Pod metadata: creationTimestamp: null labels: + io.kompose.network/v2-default: "true" io.kompose.service: foo name: foo spec: @@ -194,6 +195,22 @@ spec: - 1234 status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: v2-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/v2-default: "true" + podSelector: + matchLabels: + io.kompose.network/v2-default: "true" + --- apiVersion: apps/v1 kind: Deployment @@ -216,6 +233,7 @@ spec: kompose.service.type: loadbalancer creationTimestamp: null labels: + io.kompose.network/v2-default: "true" io.kompose.service: redis spec: containers: diff --git a/script/test/fixtures/v2/output-os.yaml b/script/test/fixtures/v2/output-os.yaml index 59c230df..4b33eb4d 100644 --- a/script/test/fixtures/v2/output-os.yaml +++ b/script/test/fixtures/v2/output-os.yaml @@ -138,6 +138,7 @@ kind: Pod metadata: creationTimestamp: null labels: + io.kompose.network/v2-default: "true" io.kompose.service: foo name: foo spec: @@ -214,6 +215,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/v2-default: "true" io.kompose.service: redis spec: containers: diff --git a/script/test/fixtures/v3.0/output-k8s.yaml b/script/test/fixtures/v3.0/output-k8s.yaml index 2a2f6f9a..f8b6dd80 100644 --- a/script/test/fixtures/v3.0/output-k8s.yaml +++ b/script/test/fixtures/v3.0/output-k8s.yaml @@ -38,7 +38,7 @@ spec: creationTimestamp: null labels: io.kompose.network/app-network: "true" - io.kompose.network/normalized-network: "true" + io.kompose.network/v30-normalized-network: "true" io.kompose.network/web-network: "true" io.kompose.service: foo spec: @@ -90,16 +90,16 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: creationTimestamp: null - name: normalized-network + name: v30-normalized-network spec: ingress: - from: - podSelector: matchLabels: - io.kompose.network/normalized-network: "true" + io.kompose.network/v30-normalized-network: "true" podSelector: matchLabels: - io.kompose.network/normalized-network: "true" + io.kompose.network/v30-normalized-network: "true" --- apiVersion: apps/v1 @@ -123,6 +123,7 @@ spec: kompose.service.type: headless creationTimestamp: null labels: + io.kompose.network/v30-default: "true" io.kompose.service: redis spec: containers: @@ -139,3 +140,19 @@ spec: restartPolicy: Always status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: v30-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/v30-default: "true" + podSelector: + matchLabels: + io.kompose.network/v30-default: "true" + diff --git a/script/test/fixtures/v3.0/output-os.yaml b/script/test/fixtures/v3.0/output-os.yaml index edb58a33..7d4e0548 100644 --- a/script/test/fixtures/v3.0/output-os.yaml +++ b/script/test/fixtures/v3.0/output-os.yaml @@ -38,7 +38,7 @@ spec: creationTimestamp: null labels: io.kompose.network/app-network: "true" - io.kompose.network/normalized-network: "true" + io.kompose.network/v30-normalized-network: "true" io.kompose.network/web-network: "true" io.kompose.service: foo spec: @@ -114,6 +114,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/v30-default: "true" io.kompose.service: redis spec: containers: diff --git a/script/test/fixtures/volume-mounts/windows/output-k8s.yaml b/script/test/fixtures/volume-mounts/windows/output-k8s.yaml index 223c7a41..42d84998 100644 --- a/script/test/fixtures/volume-mounts/windows/output-k8s.yaml +++ b/script/test/fixtures/volume-mounts/windows/output-k8s.yaml @@ -35,6 +35,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/windows-default: "true" io.kompose.service: db spec: containers: @@ -69,3 +70,19 @@ spec: storage: 100Mi status: {} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + creationTimestamp: null + name: windows-default +spec: + ingress: + - from: + - podSelector: + matchLabels: + io.kompose.network/windows-default: "true" + podSelector: + matchLabels: + io.kompose.network/windows-default: "true" + diff --git a/script/test/fixtures/volume-mounts/windows/output-os.yaml b/script/test/fixtures/volume-mounts/windows/output-os.yaml index a0f50159..c6e15b05 100644 --- a/script/test/fixtures/volume-mounts/windows/output-os.yaml +++ b/script/test/fixtures/volume-mounts/windows/output-os.yaml @@ -35,6 +35,7 @@ spec: metadata: creationTimestamp: null labels: + io.kompose.network/windows-default: "true" io.kompose.service: db spec: containers: diff --git a/script/test_in_container/Dockerfile b/script/test_in_container/Dockerfile index 62d7fc21..70ddffed 100644 --- a/script/test_in_container/Dockerfile +++ b/script/test_in_container/Dockerfile @@ -36,7 +36,7 @@ ENV PATH="$PATH:$GOPATH/bin:$GOROOT/bin" \ WORKDIR /tmp/go RUN curl https://storage.googleapis.com/golang/go$GOVERSION.linux-amd64.tar.gz | tar -xz -C /usr/local -RUN go get golang.org/x/lint/golint +RUN go get honnef.co/go/tools/cmd/staticcheck@latest WORKDIR $KOMPOSE_SRC # This image can be run as any user