diff --git a/.dockerignore b/.dockerignore
index a21b7936..13524876 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,4 +1,5 @@
.git/
+.github/
+.idea/
+.vscode/
bin/
-dist/
-tests/node-client/node_modules/
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 9c91b799..00000000
--- a/.gitattributes
+++ /dev/null
@@ -1,2 +0,0 @@
-core.autocrlf false
-*.golden text eol=lf
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9ed7a0f3..efaf62c0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,4 +19,7 @@ jobs:
go-version-file: go.mod
- name: Test
- run: make -f builder.Makefile test
+ run: go test -C go -v ./...
+
+ - name: Build compose-ecs
+ run: go build -v ./cmd
diff --git a/.github/workflows/ecs-tests.yml b/.github/workflows/ecs-tests.yml
deleted file mode 100644
index ffa00d62..00000000
--- a/.github/workflows/ecs-tests.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: ECS integration tests
-
-on:
- pull_request:
- push:
- branches:
- - main
-
-jobs:
- ecs-tests:
- name: ECS e2e tests
-
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Setup Go
- uses: actions/setup-go@v5.0.0
- with:
- cache-dependency-path: go.sum
- go-version-file: go.mod
-
- - name: Build for ECS e2e tests
- run: make -f builder.Makefile cli
-
- - name: create aws config folder
- run: mkdir -p ~/.aws
-
- - name: ECS e2e Test
- env:
- AWS_DEFAULT_REGION: us-east-1
- AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }}
- AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
- run: make e2e-ecs
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
deleted file mode 100644
index c0294b5f..00000000
--- a/.github/workflows/labeler.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-name: Labeler
-
-on:
- pull_request:
-
-jobs:
- triage:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/labeler@v2.1.1
- with:
- repo-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 0b9b1f52..8e58c682 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
+.idea/
+.vscode/
bin/
-/.idea/
-/.vscode/
diff --git a/.golangci.yml b/.golangci.yml
deleted file mode 100644
index 0a31036a..00000000
--- a/.golangci.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-linters:
- run:
- concurrency: 2
- skip-dirs:
- - tests/composefiles
- enable-all: false
- disable-all: true
- enable:
- - errcheck
- - gocyclo
- - gofmt
- - goimports
- - gosimple
- - govet
- - ineffassign
- - lll
- - misspell
- - nakedret
- - staticcheck
- - typecheck
- - unconvert
- - unparam
- - unused
-linters-settings:
- gocyclo:
- min-complexity: 16
- lll:
- line-length: 200
- goimports:
- local-prefixes: github.com/docker/compose-ecs
-issues:
- exclude:
- - should not use dot imports
diff --git a/BUILDING.md b/BUILDING.md
deleted file mode 100644
index e936bcd2..00000000
--- a/BUILDING.md
+++ /dev/null
@@ -1,82 +0,0 @@
-
-### Prerequisites
-
-* Windows:
- * [Docker Desktop](https://hub.docker.com/editions/community/docker-ce-desktop-windows)
- * make
-* macOS:
- * [Docker Desktop](https://hub.docker.com/editions/community/docker-ce-desktop-mac)
- * make
-* Linux:
- * [Docker 19.03 or later](https://docs.docker.com/engine/install/)
- * make
-
-### Building the CLI
-
-Once you have the prerequisites installed, you can build the CLI using:
-
-```console
-make
-```
-
-This will output a CLI for your host machine in `./bin`.
-
-You will then need to make sure that you have the existing Docker CLI in your
-`PATH` with the name `com.docker.cli`.
-
-You can statically cross compile the CLI for Windows, macOS, and Linux using the
-`cross` target.
-
-### Updating the API code
-
-The API provided by the CLI is defined using protobuf. If you make changes to
-the `.proto` files in [`protos/`](./protos), you will need to regenerate the API
-code:
-
-```console
-make protos
-```
-
-### Unit tests
-
-To run all of the unit tests, run:
-
-```console
-make test
-```
-
-If you need to update a golden file simply do `go test ./... -test.update-golden`.
-
-### End to end tests
-
-#### Local tests
-
-To run the local end to end tests, run:
-
-```console
-make e2e-local
-```
-
-Note that this requires the CLI to be built and a local Docker Engine to be
-running.
-
-#### ECS tests
-
-To run the end to end ECS tests, you will need to have an AWS account and have
-credentials for it in the `~/.aws/credentials` file.
-
-You can then use the `e2e-ecs` target:
-
-```console
-TEST_AWS_PROFILE=myProfile TEST_AWS_REGION=eu-west-3 make e2e-ecs
-```
-
-## Releases
-
-To create a new release:
-* Check that the CI is green on the main branch for commit you want to release
-* Create a new tag of the form vx.y.z, following existing tags, and push the tag
-
-Pushing the tag will automatically create a new release and make binaries for
-Windows, macOS, and Linux available for download on the
-[releases page](https://github.com/docker/compose-ecs/releases).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index 060f9015..00000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,326 +0,0 @@
-# Contributing to Docker
-
-Want to hack on Docker? Awesome! We have a contributor's guide that explains
-[setting up a Docker development environment and the contribution
-process](https://docs.docker.com/opensource/project/who-written-for/).
-
-This page contains information about reporting issues as well as some tips and
-guidelines useful to experienced open source contributors. Finally, make sure
-you read our [community guidelines](#docker-community-guidelines) before you
-start participating.
-
-## Topics
-
-* [Reporting Security Issues](#reporting-security-issues)
-* [Design and Cleanup Proposals](#design-and-cleanup-proposals)
-* [Reporting Issues](#reporting-other-issues)
-* [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines)
-* [Community Guidelines](#docker-community-guidelines)
-
-## Reporting security issues
-
-The Docker maintainers take security seriously. If you discover a security
-issue, please bring it to their attention right away!
-
-Please **DO NOT** file a public issue, instead send your report privately to
-[security@docker.com](mailto:security@docker.com).
-
-Security reports are greatly appreciated and we will publicly thank you for it.
-We also like to send gifts—if you're into Docker swag, make sure to let
-us know. We currently do not offer a paid security bounty program, but are not
-ruling it out in the future.
-
-
-## Reporting other issues
-
-A great way to contribute to the project is to send a detailed report when you
-encounter an issue. We always appreciate a well-written, thorough bug report,
-and will thank you for it!
-
-Check that [our issue database](https://github.com/docker/compose-ecs/issues)
-doesn't already include that problem or suggestion before submitting an issue.
-If you find a match, you can use the "subscribe" button to get notified on
-updates. Do *not* leave random "+1" or "I have this too" comments, as they
-only clutter the discussion, and don't help to resolve it. However, if you
-have ways to reproduce the issue or have additional information that may help
-resolving the issue, please leave a comment.
-
-When reporting issues, always include:
-
-* The output of `docker version`.
-* The output of `docker context show`.
-* The output of `docker info`.
-
-Also include the steps required to reproduce the problem if possible and
-applicable. This information will help us review and fix your issue faster.
-When sending lengthy log files, consider posting them as a gist
-(https://gist.github.com).
-Don't forget to remove sensitive data from your log files before posting (you
-can replace those parts with "REDACTED").
-
-## Quick contribution tips and guidelines
-
-This section gives the experienced contributor some tips and guidelines.
-
-### Pull requests are always welcome
-
-Not sure if that typo is worth a pull request? Found a bug and know how to fix
-it? Do it! We will appreciate it. Any significant change, like adding a backend,
-should be documented as
-[a GitHub issue](https://github.com/docker/compose-ecs/issues)
-before anybody starts working on it.
-
-We are always thrilled to receive pull requests. We do our best to process them
-quickly. If your pull request is not accepted on the first try,
-don't get discouraged! Our contributor's guide explains
-[the review process we use for simple changes](https://docs.docker.com/opensource/workflow/make-a-contribution/).
-
-### Talking to other Docker users and contributors
-
-
-
-
-
- Community Slack |
-
- The Docker Community has a dedicated Slack chat to discuss features and issues. You can sign-up with this link.
- |
-
-
- Forums |
-
- A public forum for users to discuss questions and explore current design patterns and
- best practices about Docker and related projects in the Docker Ecosystem. To participate,
- just log in with your Docker Hub account on https://forums.docker.com.
- |
-
-
- Twitter |
-
- You can follow Docker's Twitter feed
- to get updates on our products. You can also tweet us questions or just
- share blogs or stories.
- |
-
-
- Stack Overflow |
-
- Stack Overflow has over 17000 Docker questions listed. We regularly
- monitor Docker questions
- and so do many other knowledgeable Docker users.
- |
-
-
-
-
-### Conventions
-
-Fork the repository and make changes on your fork in a feature branch:
-
-- If it's a bug fix branch, name it XXXX-something where XXXX is the number of
- the issue.
-- If it's a feature branch, create an enhancement issue to announce
- your intentions, and name it XXXX-something where XXXX is the number of the
- issue.
-
-Submit unit tests for your changes. Go has a great test framework built in; use
-it! Take a look at existing tests for inspiration. [Run the full test
-suite](README.md) on your branch before
-submitting a pull request.
-
-Write clean code. Universally formatted code promotes ease of writing, reading,
-and maintenance. Always run `gofmt -s -w file.go` on each changed file before
-committing your changes. Most editors have plug-ins that do this automatically.
-
-Pull request descriptions should be as clear as possible and include a reference
-to all the issues that they address.
-
-Commit messages must start with a capitalized and short summary (max. 50 chars)
-written in the imperative, followed by an optional, more detailed explanatory
-text which is separated from the summary by an empty line.
-
-Code review comments may be added to your pull request. Discuss, then make the
-suggested modifications and push additional commits to your feature branch. Post
-a comment after pushing. New commits show up in the pull request automatically,
-but the reviewers are notified only when you comment.
-
-Pull requests must be cleanly rebased on top of master without multiple branches
-mixed into the PR.
-
-**Git tip**: If your PR no longer merges cleanly, use `rebase master` in your
-feature branch to update your pull request rather than `merge master`.
-
-Before you make a pull request, squash your commits into logical units of work
-using `git rebase -i` and `git push -f`. A logical unit of work is a consistent
-set of patches that should be reviewed together: for example, upgrading the
-version of a vendored dependency and taking advantage of its now available new
-feature constitute two separate units of work. Implementing a new function and
-calling it in another file constitute a single logical unit of work. The very
-high majority of submissions should have a single commit, so if in doubt: squash
-down to one.
-
-After every commit, make sure the test suite passes. Include documentation
-changes in the same pull request so that a revert would remove all traces of
-the feature or fix.
-
-Include an issue reference like `Closes #XXXX` or `Fixes #XXXX` in the pull
-request description that close an issue. Including references automatically
-closes the issue on a merge.
-
-Please do not add yourself to the `AUTHORS` file, as it is regenerated regularly
-from the Git history.
-
-Please see the [Coding Style](#coding-style) for further guidelines.
-
-### Merge approval
-
-Docker maintainers use LGTM (Looks Good To Me) in comments on the code review to
-indicate acceptance.
-
-A change requires at least 2 LGTMs from the maintainers of each
-component affected.
-
-For more details, see the [MAINTAINERS](MAINTAINERS) page.
-
-### Sign your work
-
-The sign-off is a simple line at the end of the explanation for the patch. Your
-signature certifies that you wrote the patch or otherwise have the right to pass
-it on as an open-source patch. The rules are pretty simple: if you can certify
-the below (from [developercertificate.org](http://developercertificate.org/)):
-
-```
-Developer Certificate of Origin
-Version 1.1
-
-Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
-660 York Street, Suite 102,
-San Francisco, CA 94110 USA
-
-Everyone is permitted to copy and distribute verbatim copies of this
-license document, but changing it is not allowed.
-
-Developer's Certificate of Origin 1.1
-
-By making a contribution to this project, I certify that:
-
-(a) The contribution was created in whole or in part by me and I
- have the right to submit it under the open source license
- indicated in the file; or
-
-(b) The contribution is based upon previous work that, to the best
- of my knowledge, is covered under an appropriate open source
- license and I have the right under that license to submit that
- work with modifications, whether created in whole or in part
- by me, under the same open source license (unless I am
- permitted to submit under a different license), as indicated
- in the file; or
-
-(c) The contribution was provided directly to me by some other
- person who certified (a), (b) or (c) and I have not modified
- it.
-
-(d) I understand and agree that this project and the contribution
- are public and that a record of the contribution (including all
- personal information I submit with it, including my sign-off) is
- maintained indefinitely and may be redistributed consistent with
- this project or the open source license(s) involved.
-```
-
-Then you just add a line to every git commit message:
-
- Signed-off-by: Joe Smith
-
-Use your real name (sorry, no pseudonyms or anonymous contributions.)
-
-If you set your `user.name` and `user.email` git configs, you can sign your
-commit automatically with `git commit -s`.
-
-### How can I become a maintainer?
-
-The procedures for adding new maintainers are explained in the global
-[MAINTAINERS](https://github.com/docker/opensource/blob/master/MAINTAINERS)
-file in the
-[https://github.com/docker/opensource/](https://github.com/docker/opensource/)
-repository.
-
-Don't forget: being a maintainer is a time investment. Make sure you
-will have time to make yourself available. You don't have to be a
-maintainer to make a difference on the project!
-
-## Docker community guidelines
-
-We want to keep the Docker community awesome, growing and collaborative. We need
-your help to keep it that way. To help with this we've come up with some general
-guidelines for the community as a whole:
-
-* Be nice: Be courteous, respectful and polite to fellow community members:
- no regional, racial, gender, or other abuse will be tolerated. We like
- nice people way better than mean ones!
-
-* Encourage diversity and participation: Make everyone in our community feel
- welcome, regardless of their background and the extent of their
- contributions, and do everything possible to encourage participation in
- our community.
-
-* Keep it legal: Basically, don't get us in trouble. Share only content that
- you own, do not share private or sensitive information, and don't break
- the law.
-
-* Stay on topic: Make sure that you are posting to the correct channel and
- avoid off-topic discussions. Remember when you update an issue or respond
- to an email you are potentially sending to a large number of people. Please
- consider this before you update. Also remember that nobody likes spam.
-
-* Don't send email to the maintainers: There's no need to send email to the
- maintainers to ask them to investigate an issue or to take a look at a
- pull request. Instead of sending an email, GitHub mentions should be
- used to ping maintainers to review a pull request, a proposal or an
- issue.
-
-## Coding Style
-
-Unless explicitly stated, we follow all coding guidelines from the Go
-community. While some of these standards may seem arbitrary, they somehow seem
-to result in a solid, consistent codebase.
-
-It is possible that the code base does not currently comply with these
-guidelines. We are not looking for a massive PR that fixes this, since that
-goes against the spirit of the guidelines. All new contributions should make a
-best effort to clean up and make the code base better than they left it.
-Obviously, apply your best judgement. Remember, the goal here is to make the
-code base easier for humans to navigate and understand. Always keep that in
-mind when nudging others to comply.
-
-The rules:
-
-1. All code should be formatted with `gofmt -s`.
-2. All code should pass the default levels of
- [`golint`](https://github.com/golang/lint).
-3. All code should follow the guidelines covered in [Effective
- Go](http://golang.org/doc/effective_go.html) and [Go Code Review
- Comments](https://github.com/golang/go/wiki/CodeReviewComments).
-4. Comment the code. Tell us the why, the history and the context.
-5. Document _all_ declarations and methods, even private ones. Declare
- expectations, caveats and anything else that may be important. If a type
- gets exported, having the comments already there will ensure it's ready.
-6. Variable name length should be proportional to its context and no longer.
- `noCommaALongVariableNameLikeThisIsNotMoreClearWhenASimpleCommentWouldDo`.
- In practice, short methods will have short variable names and globals will
- have longer names.
-7. No underscores in package names. If you need a compound name, step back,
- and re-examine why you need a compound name. If you still think you need a
- compound name, lose the underscore.
-8. No utils or helpers packages. If a function is not general enough to
- warrant its own package, it has not been written generally enough to be a
- part of a util package. Just leave it unexported and well-documented.
-9. All tests should run with `go test` and outside tooling should not be
- required. No, we don't need another unit testing framework. Assertion
- packages are acceptable if they provide _real_ incremental value.
-10. Even though we call these "rules" above, they are actually just
- guidelines. Since you've read all the rules, you now know that.
-
-If you are having trouble getting into the mood of idiomatic Go, we recommend
-reading through [Effective Go](https://golang.org/doc/effective_go.html). The
-[Go Blog](https://blog.golang.org) is also a great resource. Drinking the
-kool-aid is a lot easier than going thirsty.
diff --git a/Dockerfile b/Dockerfile
index b3abf3a0..720b918d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,124 +1,32 @@
# syntax = docker/dockerfile:1.6
+FROM --platform=${BUILDPLATFORM} golang:1.22.0-alpine AS build
-# Copyright 2020 Docker Compose CLI authors
+WORKDIR /go/src/
-# 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
+COPY --link --from=root go.mod .
+COPY --link --from=root go.sum .
-# 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.
-
-FROM --platform=${BUILDPLATFORM} golang:1.22.0-alpine AS base
-WORKDIR /compose-ecs
-RUN apk add --no-cache -vv \
- git \
- docker \
- make \
- protoc \
- protobuf-dev
-COPY go.* .
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go mod download
-FROM base AS make-protos
-RUN go install github.com/golang/protobuf/protoc-gen-go@v1.5.2
-COPY . .
-RUN make -f builder.Makefile protos
-
-FROM golangci/golangci-lint:v1.50.1-alpine AS lint-base
-
-FROM base AS lint
-ENV GOFLAGS="-buildvcs=false"
-ENV CGO_ENABLED=0
-COPY --from=lint-base --link /usr/bin/golangci-lint /usr/bin/golangci-lint
-ARG BUILD_TAGS
-ARG GIT_TAG
-RUN --mount=target=. \
- --mount=type=cache,target=/go/pkg/mod \
- --mount=type=cache,target=/root/.cache/go-build \
- --mount=type=cache,target=/root/.cache/golangci-lint \
- BUILD_TAGS=${BUILD_TAGS} \
- GIT_TAG=${GIT_TAG} \
- make -f builder.Makefile lint
-
-FROM base AS import-restrictions-base
-RUN go install github.com/docker/import-restrictions@latest
-
-FROM import-restrictions-base AS import-restrictions
-RUN --mount=target=. \
- --mount=type=cache,target=/go/pkg/mod \
- --mount=type=cache,target=/root/.cache/go-build \
- make -f builder.Makefile import-restrictions
-
-FROM base AS make-cli
-ENV CGO_ENABLED=0
-ARG TARGETOS
-ARG TARGETARCH
-ARG BUILD_TAGS
-ARG GIT_TAG
-RUN --mount=target=. \
- --mount=type=cache,target=/go/pkg/mod \
- --mount=type=cache,target=/root/.cache/go-build \
- GOOS=${TARGETOS} \
- GOARCH=${TARGETARCH} \
- BUILD_TAGS=${BUILD_TAGS} \
- GIT_TAG=${GIT_TAG} \
- make BINARY=/out/compose-ecs -f builder.Makefile cli
+COPY --link --from=root . .
-FROM base AS make-cross
-ARG BUILD_TAGS
-ARG GIT_TAG
-RUN --mount=target=. \
- --mount=type=cache,target=/go/pkg/mod \
+ARG VERSION
+RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
- BUILD_TAGS=${BUILD_TAGS} \
- GIT_TAG=${GIT_TAG} \
- make BINARY=/out/docker -f builder.Makefile cross
+ CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags="-s -w -X 'cmd/main.version=${VERSION}'" -o /app/compose-ecs ./cmd/main.go
-FROM scratch AS protos
-COPY --from=make-protos --link /compose-ecs/cli/server/protos .
+FROM --platform="$TARGETPLATFORM" alpine AS certs
-FROM scratch AS cli
-COPY --from=make-cli --link /out/* .
+RUN apk add --no-cache --update ca-certificates-bundle
-FROM scratch AS cross
-COPY --from=make-cross --link /out/* .
+FROM --platform="$TARGETPLATFORM" scratch
-FROM base AS test
-ENV CGO_ENABLED=0
-ARG BUILD_TAGS
-ARG GIT_TAG
-RUN --mount=target=. \
- --mount=type=cache,target=/go/pkg/mod \
- --mount=type=cache,target=/root/.cache/go-build \
- BUILD_TAGS=${BUILD_TAGS} \
- GIT_TAG=${GIT_TAG} \
- make -f builder.Makefile test
+COPY --link --from=build /app/compose-ecs /usr/local/bin/
+COPY --link --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
-FROM base AS check-license-headers
-RUN go install github.com/google/addlicense@latest
-RUN --mount=target=. \
- make -f builder.Makefile check-license-headers
+USER 1001:1001
-FROM base AS make-go-mod-tidy
-COPY . .
-RUN --mount=type=cache,target=/go/pkg/mod \
- --mount=type=cache,target=/root/.cache/go-build \
- go mod tidy
-
-FROM scratch AS go-mod-tidy
-COPY --from=make-go-mod-tidy --link /compose-ecs/go.mod .
-COPY --from=make-go-mod-tidy --link /compose-ecs/go.sum .
-
-FROM base AS check-go-mod
-COPY . .
-RUN --mount=type=cache,target=/go/pkg/mod \
- --mount=type=cache,target=/root/.cache/go-build \
- make -f builder.Makefile check-go-mod
+CMD []
+ENTRYPOINT ["compose-ecs"]
diff --git a/INSTALL.md b/INSTALL.md
deleted file mode 100644
index 9f862d84..00000000
--- a/INSTALL.md
+++ /dev/null
@@ -1,106 +0,0 @@
-# Mac and Windows installation
-
-The Compose CLI is built into Docker Desktop Edge and Stable.
-You can download it from these links:
-- [macOS](https://hub.docker.com/editions/community/docker-ce-desktop-mac)
-- [Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows)
-
-# Ubuntu Linux installation
-
-The Linux installation script and manual install instructions have been tested
-with a fresh install of Ubuntu 20.04.
-
-## Prerequisites
-
-* [Docker 19.03 or later](https://docs.docker.com/engine/install/)
-
-## Install script
-
-You can install the Compose CLI using the install script:
-
-```console
-curl -L https://raw.githubusercontent.com/docker/compose-ecs/main/scripts/install/install_linux.sh | sh
-```
-
-## Manual install
-
-You can download the Compose CLI from [latest release](https://github.com/docker/compose-ecs/releases/latest).
-
-You will then need to rename it and make it executable (the commands below assumes you downloaded the `amd64` version of the binary):
-
-```console
-$ mv docker-linux-amd64 docker
-$ chmod +x docker
-```
-
-To enable using the local Docker Engine and to use existing Docker contexts, you
-will need to have the existing Docker CLI as `com.docker.cli` somewhere in your
-`PATH`. You can do this by creating a symbolic link from the existing Docker
-CLI.
-
-```console
-ln -s /path/to/existing/docker /directory/in/PATH/com.docker.cli
-```
-
-> **Note**: The `PATH` environment variable is a colon separated list of
-> directories with priority from left to right. You can view it using
-> `echo $PATH`. You can find the path to the existing Docker CLI using
-> `which docker`. You may need root permissions to make this link.
-
-On a fresh install of Ubuntu 20.04 with Docker Engine
-[already installed](https://docs.docker.com/engine/install/ubuntu/):
-
-```console
-$ echo $PATH
-/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
-$ which docker
-/usr/bin/docker
-$ sudo ln -s /usr/bin/docker /usr/local/bin/com.docker.cli
-```
-
-You can verify that this is working by checking that the new CLI works with the
-default context:
-
-```console
-$ ./docker --context default ps
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-$ echo $?
-0
-```
-
-To make the Compose CLI your default Docker CLI, you must move it to a directory
-in your `PATH` with higher priority than the existing Docker CLI.
-
-Again on a fresh Ubuntu 20.04:
-
-```console
-$ which docker
-/usr/bin/docker
-$ echo $PATH
-/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
-$ sudo mv docker /usr/local/bin/docker
-$ which docker
-/usr/local/bin/docker
-$ docker version
-...
- Cloud integration 1.0.17
-...
-```
-
-# Uninstall
-
-To remove this CLI, you need to remove the binary you downloaded and
-`com.docker.cli` from your `PATH`. If you installed using the script, this can
-be done as follows:
-
-```console
-sudo rm /usr/local/bin/docker /usr/local/bin/com.docker.cli
-```
-
-# Testing the install script
-
-To test the install script, from a machine with docker:
-
-```console
-docker build -t testclilinux -f scripts/Dockerfile-testInstall scripts
-```
diff --git a/MAINTAINERS b/MAINTAINERS
deleted file mode 100644
index 762e2746..00000000
--- a/MAINTAINERS
+++ /dev/null
@@ -1,57 +0,0 @@
-# Docker maintainers file
-#
-# This file describes who runs the docker/compose-ecs project and how.
-# This is a living document - if you see something out of date or missing, speak up!
-#
-# It is structured to be consumable by both humans and programs.
-# To extract its contents programmatically, use any TOML-compliant
-# parser.
-#
-# This file is compiled into the MAINTAINERS file in docker/opensource.
-#
-[Org]
-
- [Org."Core maintainers"]
-
- # The Core maintainers are the ghostbusters of the project: when there's a problem others
- # can't solve, they show up and fix it with bizarre devices and weaponry.
- # They have final say on technical implementation and coding style.
- # They are ultimately responsible for quality in all its forms: usability polish,
- # bugfixes, performance, stability, etc. When ownership can cleanly be passed to
- # a subsystem, they are responsible for doing so and holding the
- # subsystem maintainers accountable. If ownership is unclear, they are the de facto owners.
-
- people = [
- "rumpl",
- "gtardif",
- "ndeloof"
- "chris-crone"
- ]
-
-[people]
-
-# A reference list of all people associated with the project.
-# All other sections should refer to people by their canonical key
-# in the people section.
-
- # ADD YOURSELF HERE IN ALPHABETICAL ORDER
-
- [people.chris-crone]
- Name = "Christopher Crone"
- Email = "christopher.crone@docker.com"
- GitHub = "chris-crone"
-
- [people.gtardif]
- Name = "Guillaume Tardif"
- Email = "guillaume.tardif@docker.com"
- GitHub = "gtardif"
-
- [people.ndeloof]
- Name = "Nicolas Deloof"
- Email = "nicolas.deloof@docker.com"
- GitHub = "ndeloof"
-
- [people.rumpl]
- Name = "Djordje Lukic"
- Email = "djordje.lukic@docker.com"
- GitHub = "rumpl"
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 3cd1f60b..00000000
--- a/Makefile
+++ /dev/null
@@ -1,107 +0,0 @@
-# Copyright 2020 Docker Compose CLI authors
-
-# 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.
-
-export DOCKER_BUILDKIT=1
-
-UNAME_S := $(shell uname -s)
-ifeq ($(UNAME_S),Linux)
- MOBY_DOCKER=/usr/bin/docker
-endif
-ifeq ($(UNAME_S),Darwin)
- MOBY_DOCKER=/Applications/Docker.app/Contents/Resources/bin/docker
-endif
-
-BINARY_FOLDER=$(shell pwd)/bin
-GIT_TAG?=$(shell git describe --tags --match "v[0-9]*")
-TEST_FLAGS?=
-E2E_TEST?=
-ifeq ($(E2E_TEST),)
-else
- TEST_FLAGS=-run $(E2E_TEST)
-endif
-
-all: cli
-
-cli: ## Compile the cli
- @docker build . --target cli \
- --platform local \
- --build-arg BUILD_TAGS=e2e \
- --build-arg GIT_TAG=$(GIT_TAG) \
- --output ./bin
-
-e2e-win-ci: ## Run end to end local tests on Windows CI, no Docker for Linux containers available ATM. Set E2E_TEST=TestName to run a single test
- go test -count=1 -v $(TEST_FLAGS) ./local/e2e/cli-only
-
-e2e-ecs: cli ## Run End to end ECS tests. Set E2E_TEST=TestName to run a single test
- go test -timeout 30m -count=1 -v $(TEST_FLAGS) ./ecs/e2e/ecs
-
-cross: ## Compile the CLI for linux, darwin and windows
- @docker build . --target cross \
- --build-arg BUILD_TAGS \
- --build-arg GIT_TAG=$(GIT_TAG) \
- --output ./bin \
-
-test: ## Run unit tests
- @docker build --progress=plain . \
- --build-arg GIT_TAG=$(GIT_TAG) \
- --target test
-
-cache-clear: ## Clear the builder cache
- @docker builder prune --force --filter type=exec.cachemount --filter=unused-for=24h
-
-lint: ## run linter(s)
- @docker build . \
- --build-arg BUILD_TAGS=e2e \
- --build-arg GIT_TAG=$(GIT_TAG) \
- --target lint
-
-check-dependencies: ## check dependency updates
- go list -u -m -f '{{if not .Indirect}}{{if .Update}}{{.}}{{end}}{{end}}' all
-
-import-restrictions: ## run import-restrictions script
- @docker build . \
- --target import-restrictions
-
-validate-headers: ## Check license header for all files
- @docker build . --target check-license-headers
-
-go-mod-tidy: ## Run go mod tidy in a container and output resulting go.mod and go.sum
- @docker build . --target go-mod-tidy --output .
-
-validate-go-mod: ## Validate go.mod and go.sum are up-to-date
- @docker build . --target check-go-mod
-
-validate: validate-go-mod validate-headers ## Validate sources
-
-pre-commit: validate import-restrictions check-dependencies lint cli test
-
-build-ecs-search-sidecar: ## build ecs search sidecar image locally and tag it with make build-ecs-search-sidecar tag=0.1
- docker buildx build --platform linux/amd64,linux/arm64 -t docker/ecs-searchdomain-sidecar:$(tag) ecs/resolv
-
-publish-ecs-search-sidecar: build-ecs-search-sidecar ## build & publish ecs search sidecar image with make publish-ecs-search-sidecar tag=0.1
- docker pull docker/ecs-searchdomain-sidecar:$(tag) && echo "Failure: Tag already exists" || docker buildx build --push --platform linux/amd64,linux/arm64 -t docker/ecs-searchdomain-sidecar:$(tag) ecs/resolv
-
-build-ecs-secrets-sidecar: ## build ecs secrets sidecar image locally and tag it with make build-ecs-secrets-sidecar tag=0.1
- docker buildx build --platform linux/amd64,linux/arm64 -t docker/ecs-secrets-sidecar:$(tag) ecs/secrets
-
-publish-ecs-secrets-sidecar: build-ecs-secrets-sidecar ## build & publish ecs secrets sidecar image with make publish-ecs-secrets-sidecar tag=0.1
- docker pull docker/ecs-secrets-sidecar:$(tag) && echo "Failure: Tag already exists" || docker buildx build --push --platform linux/amd64,linux/arm64 -t docker/ecs-secrets-sidecar:$(tag) ecs/secrets
-
-help: ## Show help
- @echo Please specify a build target. The choices are:
- @grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
-
-FORCE:
-
-.PHONY: all validate cli cross test cache-clear lint check-dependencies help go-mod-tidy
diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index 265c0a05..00000000
--- a/NOTICE
+++ /dev/null
@@ -1,4 +0,0 @@
-Docker Compose CLI
-Copyright 2020 Docker Compose CLI authors
-
-This product includes software developed at Docker, Inc. (https://www.docker.com).
diff --git a/README.md b/README.md
index 63b20def..0348eb94 100644
--- a/README.md
+++ b/README.md
@@ -106,5 +106,5 @@ $ compose-ecs convert
```
-Please create [issues](https://github.com/docker/compose-ecs/issues) to leave feedback.
+Please create [issues](https://github.com/austindrenski/compose-ecs/issues) to leave feedback.
diff --git a/builder.Makefile b/builder.Makefile
deleted file mode 100644
index bc3ef1d3..00000000
--- a/builder.Makefile
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright 2020 Docker Compose CLI authors
-
-# 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.
-
-GOOS?=$(shell go env GOOS)
-GOARCH?=$(shell go env GOARCH)
-
-PKG_NAME := github.com/docker/compose-ecs
-
-GO_LDFLAGS ?= -s -w -X ${PKG}/internal.Version=${VERSION} -X ${PKG}/internal.GitCommit=${COMMIT}
-
-PROTOS=$(shell find cli/server/protos -name \*.proto)
-
-EXTENSION:=
-ifeq ($(GOOS),windows)
- EXTENSION:=.exe
-endif
-
-STATIC_FLAGS=CGO_ENABLED=0
-
-GIT_TAG?=$(shell git describe --tags --match "v[0-9]*")
-
-LDFLAGS="-s -w -X $(PKG_NAME)/internal.Version=${GIT_TAG}"
-GO_BUILD=$(STATIC_FLAGS) go build -trimpath -ldflags=$(LDFLAGS)
-
-BINARY?=bin/compose-ecs
-BINARY_WITH_EXTENSION=$(BINARY)$(EXTENSION)
-
-WORK_DIR:=$(shell mktemp -d)
-
-TAGS:=
-ifdef BUILD_TAGS
- TAGS=-tags $(BUILD_TAGS)
- LINT_TAGS=--build-tags $(BUILD_TAGS)
-endif
-
-.PHONY: protos
-protos:
- protoc -I. --go_out=plugins=grpc,paths=source_relative:. ${PROTOS}
-
-.PHONY: cli
-cli:
- GOOS=${GOOS} GOARCH=${GOARCH} $(GO_BUILD) $(TAGS) -o $(BINARY_WITH_EXTENSION) ./cli
-
-.PHONY: cross
-cross:
- GOOS=linux GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(BINARY)-linux-amd64 ./cli
- GOOS=linux GOARCH=arm64 $(GO_BUILD) $(TAGS) -o $(BINARY)-linux-arm64 ./cli
- GOOS=linux GOARM=6 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(BINARY)-linux-armv6 ./cli
- GOOS=linux GOARM=7 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(BINARY)-linux-armv7 ./cli
- GOOS=linux GOARCH=s390x $(GO_BUILD) $(TAGS) -o $(BINARY)-linux-s390x ./cli
- GOOS=darwin GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(BINARY)-darwin-amd64 ./cli
- GOOS=darwin GOARCH=arm64 $(GO_BUILD) $(TAGS) -o $(BINARY)-darwin-arm64 ./cli
- GOOS=windows GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(BINARY)-windows-amd64.exe ./cli
-
-.PHONY: test
-test:
- go test $(TAGS) -cover $(shell go list $(TAGS) ./... | grep -vE 'e2e')
-
-.PHONY: lint
-lint:
- golangci-lint run $(LINT_TAGS) --timeout 10m0s ./...
-
-.PHONY: import-restrictions
-import-restrictions:
- import-restrictions --configuration import-restrictions.yaml
-
-.PHONY: check-license-headers
-check-license-headers:
- ./scripts/validate/fileheader
-
-.PHONY: check-go-mod
-check-go-mod:
- ./scripts/validate/check-go-mod
-
-.PHONY: yamldocs
-yamldocs:
- go run docs/yaml/main/generate.go
diff --git a/cli/main.go b/cli/main.go
deleted file mode 100644
index 88780f3f..00000000
--- a/cli/main.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package main
-
-import (
- "fmt"
- "github.com/docker/cli/cli"
- "github.com/docker/cli/cli-plugins/manager"
- "github.com/docker/cli/cli-plugins/plugin"
- "github.com/docker/cli/cli/command"
- "github.com/docker/compose-ecs/ecs"
- "github.com/docker/compose-ecs/internal"
- "github.com/docker/compose/v2/cmd/compatibility"
- commands "github.com/docker/compose/v2/cmd/compose"
- "github.com/docker/compose/v2/pkg/compose"
- "github.com/spf13/cobra"
- "os"
-)
-
-func main() {
- if plugin.RunningStandalone() {
- os.Args = append([]string{"docker"}, compatibility.Convert(os.Args[1:])...)
- }
-
- plugin.Run(func(dockerCli command.Cli) *cobra.Command {
-
- service, err := ecs.NewComposeECS()
- if err != nil {
- _, _ = fmt.Fprintln(os.Stderr, err.Error())
- os.Exit(1)
- }
-
- root := &cobra.Command{
- Use: "compose-ecs",
- SilenceErrors: true,
- SilenceUsage: true,
- TraverseChildren: true,
- RunE: func(cmd *cobra.Command, args []string) error {
- if len(args) == 0 {
- return cmd.Help()
- }
- return fmt.Errorf("unknown command: %q", args[0])
- },
- }
-
- root.AddCommand(&cobra.Command{
- Use: "version",
- Short: "Show the Docker version information",
- Args: cobra.MaximumNArgs(0),
- RunE: func(cmd *cobra.Command, _ []string) error {
- fmt.Printf("Compose ECS %s\n", internal.Version)
- return nil
- },
- })
-
- rootCommand := commands.RootCommand(dockerCli, service)
-
- rootCommand.SetFlagErrorFunc(func(c *cobra.Command, err error) error {
- return cli.StatusError{
- StatusCode: compose.CommandSyntaxFailure.ExitCode,
- Status: err.Error(),
- }
- })
-
- return rootCommand
- }, manager.Metadata{
- SchemaVersion: "0.1.0",
- Vendor: "austin@austindrenski.io",
- Version: internal.Version,
- })
-}
diff --git a/cmd/main.go b/cmd/main.go
new file mode 100644
index 00000000..2fa8d703
--- /dev/null
+++ b/cmd/main.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/austindrenski/compose-ecs/ecs"
+ "github.com/docker/cli/cli-plugins/manager"
+ "github.com/docker/cli/cli-plugins/plugin"
+ "github.com/docker/cli/cli/command"
+ "github.com/docker/compose/v2/cmd/compose"
+ "github.com/spf13/cobra"
+)
+
+var version = "dev"
+
+func main() {
+ plugin.Run(func(cli command.Cli) *cobra.Command {
+ service, err := ecs.NewService(context.Background())
+
+ if err != nil {
+ _, _ = fmt.Fprintln(cli.Err(), err)
+ os.Exit(1)
+ }
+
+ return compose.RootCommand(cli, service)
+ }, manager.Metadata{
+ SchemaVersion: "0.1.0",
+ Vendor: "austin@austindrenski.io",
+ Version: version,
+ })
+}
diff --git a/docker-bake.hcl b/docker-bake.hcl
new file mode 100644
index 00000000..237c1b97
--- /dev/null
+++ b/docker-bake.hcl
@@ -0,0 +1,54 @@
+variable GITHUB_SHA { default = "$GITHUB_SHA" }
+variable GITHUB_REF_NAME { default = "$GITHUB_REF_NAME" }
+variable GITHUB_REF_TYPE { default = "$GITHUB_REF_TYPE" }
+variable REGISTRY { default = "ghcr.io/austindrenski" }
+variable VERSION { default = "0.0.1" }
+
+group default {
+ targets = [
+ "compose_ecs"
+ ]
+}
+
+target base {
+ args = {
+ VERSION = version()
+ }
+ contexts = {
+ root = "."
+ }
+ dockerfile = "Dockerfile"
+ output = [
+ "type=image"
+ ]
+ platforms = [
+ "linux/amd64",
+ "linux/arm64"
+ ]
+ pull = true
+}
+
+target compose_ecs {
+ inherits = [
+ target.base.name
+ ]
+ labels = {
+ "org.opencontainers.image.description" = "Docker CLI plugin for converting Compose => CloudFormation"
+ "org.opencontainers.image.name" = "compose-ecs"
+ "org.opencontainers.image.title" = "Docker Compose ECS conversion"
+ }
+ tags = tags(target.compose_ecs.labels)
+}
+
+function tags {
+ params = [labels]
+ result = [
+ equal(version(), VERSION) ? format("%s/%s:%s", REGISTRY, labels["org.opencontainers.image.name"], "latest") : "",
+ format("%s/%s:%s", REGISTRY, labels["org.opencontainers.image.name"], version())
+ ]
+}
+
+function version {
+ params = []
+ result = equal(GITHUB_REF_TYPE, "tag") ? trimprefix(lower(GITHUB_REF_NAME), "v") : format("%s-ci.%s", VERSION, lower(GITHUB_REF_NAME))
+}
diff --git a/docs/ecs-architecture.md b/docs/ecs-architecture.md
deleted file mode 100644
index c8d85d36..00000000
--- a/docs/ecs-architecture.md
+++ /dev/null
@@ -1,82 +0,0 @@
----
-title: ECS integration architecture
-description: Mapping of Docker compose entities to Amazon constructs
-keywords: Docker, Amazon, Integration, ECS, Compose, architecture, mapping
----
-# Architecture
-
-ECS integration relies on CloudFormation to manage AWS resources as an atomic operation.
-This document describes the mapping between compose application model and AWS components
-
-## Overview
-
-This diagram shows compose model and on same line AWS components that get created as equivalent resources
-
-```
-+----------+ +-------------+ +-------------------+
-| Project | . . . . . . . . . . . . . . | Cluster | . . . . . . . | LoadBalancer |
-+-+--------+ +-------------+ +-------------------+
- |
- | +----------+ +-------------++-------------------+ +-------------------+
- +----+ Service | . . . . . . . . . . | Service || TaskDefinition | | TargetGroup |
- | +--+-------+ +-------------++-------------------+-+ +-------------------+
- | | | TaskRole |
- | | +-------------------+-+
- | | x-aws-role, x-aws-policies . . . . . . . . | TaskExecutionRole |
- | | +-------------------+
- | | +---------+
- | +--+ Deploy |
- | | +---------+ +-------------------+
- | | x-aws-autoscaling . . . . . . | ScalableTarget |
- | | +-------------------+---+
- | | | ScalingPolicy |
- | | +-------------------+-+
- | | | AutoScalingRole |
- | | +-------------------+
- | |
- | | +---------+ +-------------+ +-------------------+
- | +--+ Ports | . . . . . . . | IngressRule +-----+ | Listener |
- | | +---------+ +-------------+ | +-------------------+
- | | |
- | | +---------+ +---------------+ +------------------+
- | +--+ Secrets | . . . . . . . | InitContainer | |TaskExecutionRole |
- | | +---------+ +---------------+ +------------+-----+
- | | | |
- | | +---------+ | |
- | +--+ Volumes | | |
- | | +---------+ | |
- | | | |
- | | +---------------+ | | +-------------------+
- | +--+ DeviceRequest | . . . . . . . . . . . . . . . | . . . . | . . . | CapacityProvider |
- | +---------------+ | | +-------------------+--------+
- | | | | AutoscalingGroup |
- | +------------+ +---------------+ | | +---------------------+
- +---+ Networks | . . . . . . . . . | SecurityGroup +---+ | | LaunchConfiguration |
- | +------------+ +---------------+ | +---------------------+
- | |
- | +------------+ +---------------+ |
- +---+ Secret | . . . . . . . . . | Secret +--------------+
- +------------+ +---------------+
-```
-
-Each compose application service is mapped to an ECS `Service`. A `TaskDefinition` is created according to compose definition.
-Actual mapping is constrained by both Cloud platform and Fargate limitations. Such a `TaskDefinition` is set with a single container,
-according to the compose model which doesn't offer a syntax to support sidecar containers.
-
-An IAM Role is created and configured as `TaskRole` to grant service access to additional AWS resources when required. For this
-purpose, user can set `x-aws-policies` or define a fine grained `x-aws-role` IAM role document.
-
-Service's ports get mapped into security group's `IngressRule`s and load balancer `Listener`s.
-Compose application with HTTP services only (using ports 80/443 or `x-aws-protocol` set to `http`) get an Application Load Balancer
-created, otherwise a Network Load Balancer is used.
-
-A `TargetGroup` is created per service to dispatch traffic by load balancer to the matching containers
-
-Secrets bound to a service get translated into an `InitContainer` added to the service's `TaskDefinition`. This init container is
-responsible to create a `/run/secrets` file for secret to match docker secret model and make application code portable.
-A `TaskExecutionRole` is also created per service, and is updated to grant access to bound secrets.
-
-Services using a GPU (`DeviceRequest`) get the `Cluster` extended with an EC2 `CapacityProvider`, using an `AutoscalingGroup` to manage
-EC2 resources allocation based on a `LaunchConfiguration`. The latter uses ECS recommended AMI and machine type for GPU.
-
-Service to declare `deploy.x-aws-autoscaling` get a `ScalingPolicy` created targeting specified the configured CPU usage metric
diff --git a/docs/ecs-compose-examples.md b/docs/ecs-compose-examples.md
deleted file mode 100644
index 9137b762..00000000
--- a/docs/ecs-compose-examples.md
+++ /dev/null
@@ -1,302 +0,0 @@
----
-title: ECS integration composefile examples
-description: Examples of ECS compose files
-keywords: Docker, Amazon, Integration, ECS, Compose, cli, deploy, cloud, sample
----
-# Compose file samples - ECS specific
-
-
-
-## Service
-
-A service mapping may define a Docker image and runtime constraints and container requirements.
-
-```yaml
-services:
- test:
- image: "image"
- command: "command"
- entrypoint: "entrypoint"
- environment:
- - "FOO=BAR"
- cap_add:
- - SYS_PTRACE
- cap_drop:
- - SYSLOG
- init: true
- user: "user"
- working_dir: "working_dir"
-```
-
-
-###### Task size
-
-Set resource limits that will get translated to Fargate task size values:
-
-```yaml
-services:
- test:
- image: nginx
- deploy:
- resources:
- limits:
- cpus: '0.5'
- memory: 2048M
-```
-
-###### IAM roles
-
-Assign an existing user role to a task:
-
-```yaml
-services:
- test:
- x-aws-policies:
- - "arn:aws:iam::aws:policy/AmazonS3FullAccess"
-```
-
-###### IAM policies
-
-Assign an in-line IAM policy to a task:
-
-```yaml
-services:
- test:
- x-aws-role:
- Version: '2012-10-17'
- Statement:
- - Effect: Allow
- Action: sqs:*
- Resource: arn:aws:sqs:us-east-1:12345678:myqueue
-```
-
-###### Logging
-Pass options to awslogs driver
-```yaml
-services:
- foo:
- image: nginx
- logging:
- options:
- awslogs-datetime-pattern: "FOO"
-
-x-aws-logs_retention: 10
-```
-
-
-###### Autoscaling
-
-Set a CPU percent target
-```yaml
-services:
- foo:
- image: nginx
- deploy:
- x-aws-autoscaling:
- cpu: 75
-```
-
-
-###### GPU
-Set `generic_resources` for services that require accelerators as GPUs.
-```yaml
-services:
- learning:
- image: tensorflow/tensorflow:latest-gpus
- deploy:
- resources:
- reservations:
- memory: 32Gb
- cpus: "32"
- generic_resources:
- - discrete_resource_spec:
- kind: gpus
- value: 2
-```
-
-
-
-
-##### Load Balancers
-
-When a service in the compose file exposes a port, a load balancer is being created and configured to distribute the traffic between all containers.
-
-There are 2 types of Load Balancers that can be created. For a service exposing a non-http port/protocol, a __Network Load Balancer (NLB)__ is created. Services with http/https ports/protocols get an __Application Load Balancer (ALB)__.
-
- There is only one load balancer created/configured for a Compose stack. If there are both http/non-http ports configured for services in a compose stack, an NLB is created.
-
-The compose file below configured only the http port,therefore, on deployment it gets an ALB created.
-
-```yaml
-services:
- app:
- image: nginx
- ports:
- - 80:80
-```
-NLB is created for non-http port
-```yaml
-services:
- app:
- image: nginx
- ports:
- - 8080:8080
-```
-
-To use the http protocol with custom ports and get an ALB, use the `x-aws-protocol` port property.
-```yaml
-services:
- test:
- image: nginx
- ports:
- - target: 8080
- x-aws-protocol: http
-```
-
-To re-use an external load balancer and avoid creating a dedicated one, set the top-level property `x-aws-loadbalancer` as below:
-```yaml
-x-aws-loadbalancer: "LoadBalancerName"
-services:
- app:
- image: nginx
- ports:
- - 80:80
-```
-
-Similarly, an external `VPC` and `Cluster` can be reused:
-
-```yaml
-x-aws-vpc: "vpc-25435e"
-x-aws-cluster: "ClusterName"
-
-services:
- app:
- image: nginx
- ports:
- - 80:80
-```
-
-Keep in mind, that external resources are not managed as part of the compose stack's lifecycle.
-
-
-## Volumes
-
-```yaml
-services:
- app:
- image: nginx
- volumes:
- - data:/test
-volumes:
- data:
-```
-To use of an external volume that has been previously created, set its id/ARN as the name:
-
-```yaml
-services:
- app:
- image: nginx
- volumes:
- - data:/test
-
-volumes:
- data:
- external: true
- name: "fs-f534645"
-```
-
-Customize volume configuration via `driver_opts`
-
-```yaml
-services:
- test:
- image: nginx
-volumes:
- db-data:
- driver_opts:
- backup_policy: ENABLED
- lifecycle_policy: AFTER_30_DAYS
- performance_mode: maxIO
- throughput_mode: provisioned
- provisioned_throughput: 1024
-```
-
-## Networks
-
-Networks are mapped to security groups.
-```yaml
-services:
- test:
- image: nginx
-networks:
- default:
-```
-Using an external network/security group:
-```yaml
-services:
- test:
- image: nginx
-networks:
- default:
- external: true
- name: sg-123abc
-```
-
-## Secrets
-Secrets are stored in __AWS SecretsManager__ as strings and are mounted to containers under `/run/secrets/`.
-```yaml
-services:
- app:
- image: nginx
- ports:
- - 80:80
- secrets:
- - mysecret
-
-secrets:
- mysecret:
- file: ./secrets/mysecret.txt
-```
-
-When using external secrets, set a valid secret `ARN` under the `name` property:
-
-```yaml
-services:
- app:
- image: nginx
- secrets:
- - foo_bar
-
-secrets:
- foo_bar:
- name: "arn:aws:secretsmanager:eu-west-3:xxx:secret:foo_bar"
- external: true
-```
-
-
-## Access private images
-When a service is configured with an image from a private repository on Docker Hub, make sure you have configured pull credentials correctly before deploying the Compose stack.
-
-To create a pull credential, create a file with the following content:
-```sh
-$ cat creds.json
-{
- "username":"DockerHubID",
- "password":"GeneratedHubTokenOrPassword"
-}
-```
-To create the pull credential and retrieve the `ARN/ID` to use in the compose file run:
-```sh
-$ docker secret create pullcred /path/to/creds.json
-arn:aws:secretsmanager:eu-west-3:xxx:secret:pullcred
-```
-
-Use the `ARN` in the output to set the `x-aws-pull_credentials` service property as below:
-```yaml
-services:
- app:
- image: DockerHubID/privateimage
- x-aws-pull_credentials: arn:aws:secretsmanager:eu-west-3:xxx:secret:pullcred
- ports:
- - 80:80
-```
diff --git a/docs/ecs-compose-features.md b/docs/ecs-compose-features.md
deleted file mode 100644
index d08e0f9c..00000000
--- a/docs/ecs-compose-features.md
+++ /dev/null
@@ -1,181 +0,0 @@
----
-title: ECS integration Compose features
-description: Reference list of compose ECS features
-keywords: Docker, Amazon, Integration, ECS, Compose, cli, deploy, cloud
----
-# Compose - Amazon ECS mapping
-
-This document outlines the conversion of an application defined in a Compose file to AWS resources.
-Each service is mapped to an ECS service in the project's cluster.
-
-## Compose fields mapping
-
-The table below lists supported Compose file fields and their AWS counterparts.
-
-__Legend:__
-
-- __✓:__ Implemented
-- __n:__ Not yet implemented
-- __x:__ Not applicable / no available conversion
-
-| Keys |Map| Notes |
-|--------------------------------|---|--------------------------------------------------------------|
-| __Service__ | ✓ |
-| service.service.build | x | Ignored. No image build support on AWS.
-| service.cap_add, cap_drop | ✓ | Supported with [Fargate limitations](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_KernelCapabilities.html)
-| service.command | ✓ |
-| service.configs | x |
-| service.cgroup_parent | x |
-| service.container_name | x |
-| service.credential_spec | x |
-| service.deploy | ✓ |
-| service.deploy.endpoint_mode | x |
-| service.deploy.mode | x |
-| service.deploy.replicas | ✓ | Set service initial scale. Auto-scaling, when enabled, will make this dynamic
-| service.deploy.placement | ✓ | Used with EC2 support to select a machine type and AMI
-| service.deploy.update_config | ✓ |
-| service.deploy.resources | ✓ | Fargate resource is selected with the lowest instance type for configured memory and cpu
-| service.deploy.restart_policy | ✓ |
-| service.deploy.labels | ✓ |
-| service.devices | x |
-| service.depends_on | ✓ | Implemented using CloudFormation Depends_on
-| service.dns | x |
-| service.dns_search | x |
-| service.domainname | x |
-| service.tmpfs | x | Not supported on Fargate, see https://github.com/docker/compose-ecs/issues/839
-| service.entrypoint | ✓ |
-| service.env_file | ✓ |
-| service.environment | ✓ |
-| service.expose | x |
-| service.extends | ✓ |
-| service.external_links | x |
-| service.extra_hosts | x |
-| service.group_add | x |
-| service.healthcheck | ✓ | This configures container level health check as reported on ECS console. Application Load Balancer will also check for HTTP service health by accessing `/` and expect a HTTP 200 status code.
-| service.hostname | x |
-| service.image | ✓ | Private images will be accessible by passing x-aws-pull_policy with ARN of a username+password secret
-| service.isolation | x |
-| service.labels | x |
-| service.links | x |
-| service.logging | ✓ | Can be used to customize CloudWatch Logs configuration
-| service.network_mode | x |
-| service.networks | x | Communication between services is implemented by SecurityGroups within the application VPC.
-| service.pid | x |
-| service.ports | ✓ | Only symetrical port mapping is supported in ECS. See [Exposing ports](#exposing-ports).
-| service.secrets | ✓ | See [Secrets](#secrets).
-| service.security_opt | x |
-| service.stop_grace_period | x |
-| service.stop_signal | x |
-| service.sysctls | x |
-| service.ulimits | ✓ | Only support `nofile` ulimit due to Fargate limitations
-| service.userns_mode | x |
-| service.volumes | ✓ | Mapped to EFS File Systems. See [Persistent volumes](#persistent-volumes).
-| service.restart | x | Replaced by service.deployment.restart_policy
-| | |
-| __Volume__ | x |
-| driver | ✓ | See [Persistent volumes](#persistent-volumes).
-| driver_opts | ✓ |
-| external | ✓ | `name` must be an EFS filesystem ID
-| labels | x |
-| | |
-| __Secret__ | x |
-| external | ✓ | `name` must be set to secret's ARN
-| file | ✓ | file content will be uploaded into AWS Secret Manager
-| | |
-| __Config__ | x |
-| | |
-
-
-## Logs
-
-Application logs can be obtained container with `docker compose logs`.
-The Docker ECS integration relies on AWS CloudWatch Logs to collect logs from all containers. CloudWatch can be customized by setting service `logging.driver_opts`
-by passing configuration attributes prefixed with `awslogs-`.
-
-```yaml
- test:
- image: mycompany/webapp
- logging:
- driver-opts:
- awslogs-datetime-pattern: "some-pattern"
-```
-
-
-## Exposing ports
-
-When one or more services expose ports, a Load Balancer is created for the application.
-As all services are exposed through the same Load Balancer, only one service can expose a given port number.
-The source and target ports defined in the Compose file MUST be the same, as service-to-service communication don't go through the Load Balancer and could not
-benefit from Listeners abstraction to assign a distinct published port.
-
-If services in the Compose file only expose ports 80 or 443, an Application Load Balancer is created, otherwise ECS integration will provision a Network Load Balancer.
-HTTP services using distinct ports can force use of an ALB by claiming the http protocol with `x-aws-protocol` custom extension within the port declaration:
-
-```yaml
- test:
- image: mycompany/webapp
- ports:
- - target: 8080
- x-aws-protocol: http
-
-```
-
-## Persistent volumes
-
-Docker volumes are mapped to EFS file systems. Volumes can be external (`name` must then be set to filesystem ID) or will be created when the application is
-first deployed. `docker compose down` will NOT delete the filesystem, and it will be re-attached to the application on future runs.
-`driver_opts` can be used to tweak the EFS filsystem.
-
-Volume mount can be customized to workaround Posix filesystem permission issues by setting user and group IDs to be used to write to filesystem, whatever user
-is configured to run the container.
-
-```yaml
-services:
- myservice:
- image: mycompany/webapp
- volumes:
- - mydata:/mount/testvolumes
-
-volumes:
- mydata:
- driver_opts:
- performance-mode: maxIO
- throughput-mode: bursting
- uid: 0
- gid: 0
-```
-
-
-## Secrets
-
-Secrets can be defined in compose files, and will need secret files available at deploy time next to the compose file.
-The content of the secret file will be made available inside selected containers, by default under `/run/secrets/`.
-External secrets are also supported, `name` must then be set to secret's ARN
-
-```yaml
-services:
- nginx:
- image: mycompany/webapp
- secrets:
- - mysecret
-
-secrets:
- mysecret:
- file: ./my_secret1.txt
-```
-
-
-## Container Resources
-
-CPU and memory limits can be set in compose. Those are used to select the minimal [Fargate size](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/AWS_Fargate.html) that will match those limits.
-
-```yaml
-services:
- nginx:
- image: mycompany/webapp
- deploy:
- resources:
- limits:
- cpus: '0.5'
- memory: 2Gb
-```
diff --git a/ecs/autoscaling.go b/ecs/autoscaling.go
deleted file mode 100644
index ffc9e6bb..00000000
--- a/ecs/autoscaling.go
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "encoding/json"
- "fmt"
-
- applicationautoscaling2 "github.com/aws/aws-sdk-go/service/applicationautoscaling"
- "github.com/awslabs/goformation/v4/cloudformation"
- "github.com/awslabs/goformation/v4/cloudformation/applicationautoscaling"
- "github.com/awslabs/goformation/v4/cloudformation/iam"
- "github.com/compose-spec/compose-go/types"
-)
-
-type autoscalingConfig struct {
- Memory int `json:"memory,omitempty"`
- CPU int `json:"cpu,omitempty"`
- Min int `json:"min,omitempty"`
- Max int `json:"max,omitempty"`
-}
-
-func (b *ComposeECS) createAutoscalingPolicy(project *types.Project, resources awsResources, template *cloudformation.Template, service types.ServiceConfig) error {
- if service.Deploy == nil {
- return nil
- }
- v, ok := service.Deploy.Extensions[extensionAutoScaling]
- if !ok {
- return nil
- }
-
- marshalled, err := json.Marshal(v)
- if err != nil {
- return err
- }
- var config autoscalingConfig
- err = json.Unmarshal(marshalled, &config)
- if err != nil {
- return err
- }
-
- if config.Memory != 0 && config.CPU != 0 {
- return fmt.Errorf("%s can't be set with both cpu and memory targets", extensionAutoScaling)
- }
- if config.Max == 0 {
- return fmt.Errorf("%s MUST define max replicas", extensionAutoScaling)
- }
-
- role := fmt.Sprintf("%sAutoScalingRole", normalizeResourceName(service.Name))
- template.Resources[role] = &iam.Role{
- AssumeRolePolicyDocument: ausocalingAssumeRolePolicyDocument,
- Path: "/",
- Policies: []iam.Role_Policy{
- {
- PolicyDocument: &PolicyDocument{
- Statement: []PolicyStatement{
- {
- Effect: "Allow",
- Action: []string{
- actionAutoScaling,
- actionDescribeService,
- actionUpdateService,
- actionGetMetrics,
- },
- Resource: []string{cloudformation.Ref(serviceResourceName(service.Name))},
- },
- },
- },
- PolicyName: "service-autoscaling",
- },
- },
- Tags: serviceTags(project, service),
- }
-
- // Why isn't this just the service ARN ?????
- resourceID := cloudformation.Join("/", []string{"service", resources.cluster.ID(), cloudformation.GetAtt(serviceResourceName(service.Name), "Name")})
-
- target := fmt.Sprintf("%sScalableTarget", normalizeResourceName(service.Name))
- template.Resources[target] = &applicationautoscaling.ScalableTarget{
- MaxCapacity: config.Max,
- MinCapacity: config.Min,
- ResourceId: resourceID,
- RoleARN: cloudformation.GetAtt(role, "Arn"),
- ScalableDimension: applicationautoscaling2.ScalableDimensionEcsServiceDesiredCount,
- ServiceNamespace: applicationautoscaling2.ServiceNamespaceEcs,
- AWSCloudFormationDependsOn: []string{serviceResourceName(service.Name)},
- }
-
- var (
- metric = applicationautoscaling2.MetricTypeEcsserviceAverageCpuutilization
- targetPercent = config.CPU
- )
- if config.Memory != 0 {
- metric = applicationautoscaling2.MetricTypeEcsserviceAverageMemoryUtilization
- targetPercent = config.Memory
- }
-
- policy := fmt.Sprintf("%sScalingPolicy", normalizeResourceName(service.Name))
- template.Resources[policy] = &applicationautoscaling.ScalingPolicy{
- PolicyType: "TargetTrackingScaling",
- PolicyName: policy,
- ScalingTargetId: cloudformation.Ref(target),
- StepScalingPolicyConfiguration: nil,
- TargetTrackingScalingPolicyConfiguration: &applicationautoscaling.ScalingPolicy_TargetTrackingScalingPolicyConfiguration{
- PredefinedMetricSpecification: &applicationautoscaling.ScalingPolicy_PredefinedMetricSpecification{
- PredefinedMetricType: metric,
- },
- ScaleOutCooldown: 60,
- ScaleInCooldown: 60,
- TargetValue: float64(targetPercent),
- },
- }
- return nil
-}
diff --git a/ecs/autoscaling_test.go b/ecs/autoscaling_test.go
deleted file mode 100644
index c8f16b5b..00000000
--- a/ecs/autoscaling_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "testing"
-
- autoscaling "github.com/awslabs/goformation/v4/cloudformation/applicationautoscaling"
- "gotest.tools/v3/assert"
-)
-
-func TestAutoScaling(t *testing.T) {
- template := convertYaml(t, `
-services:
- foo:
- image: hello_world
- deploy:
- x-aws-autoscaling:
- cpu: 75
- max: 10
-`, nil, useDefaultVPC)
- target := template.Resources["FooScalableTarget"].(*autoscaling.ScalableTarget)
- assert.Check(t, target != nil) //nolint:staticcheck
- assert.Check(t, target.MaxCapacity == 10) //nolint:staticcheck
-
- policy := template.Resources["FooScalingPolicy"].(*autoscaling.ScalingPolicy)
- assert.Check(t, policy != nil) //nolint:staticcheck
- assert.Check(t, policy.TargetTrackingScalingPolicyConfiguration.TargetValue == float64(75)) //nolint:staticcheck
-}
diff --git a/ecs/aws.go b/ecs/aws.go
deleted file mode 100644
index 9eadbe37..00000000
--- a/ecs/aws.go
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
-
- "github.com/aws/aws-sdk-go/service/cloudformation"
- "github.com/aws/aws-sdk-go/service/ecs"
- "github.com/docker/compose/v2/pkg/api"
-)
-
-const (
- awsTypeCapacityProvider = "AWS::ECS::CapacityProvider"
- awsTypeAutoscalingGroup = "AWS::AutoScaling::AutoScalingGroup"
-)
-
-//go:generate mockgen -destination=./aws_mock.go -self_package "github.com/docker/compose-ecs/ecs" -package=ecs . API
-
-// API hides aws-go-sdk into a simpler, focussed API subset
-type API interface {
- CheckRequirements(ctx context.Context, region string) error
- ResolveCluster(ctx context.Context, nameOrArn string) (awsResource, error)
- CreateCluster(ctx context.Context, name string) (string, error)
- CheckVPC(ctx context.Context, vpcID string) error
- GetDefaultVPC(ctx context.Context) (string, error)
- GetSubNets(ctx context.Context, vpcID string) ([]awsResource, error)
- IsPublicSubnet(ctx context.Context, subNetID string) (bool, error)
- GetRoleArn(ctx context.Context, name string) (string, error)
- StackExists(ctx context.Context, name string) (bool, error)
- CreateStack(ctx context.Context, name string, region string, template []byte) error
- CreateChangeSet(ctx context.Context, name string, region string, template []byte) (string, error)
- UpdateStack(ctx context.Context, changeset string) error
- WaitStackComplete(ctx context.Context, name string, operation int) error
- GetStackID(ctx context.Context, name string) (string, error)
- ListStacks(ctx context.Context) ([]api.Stack, error)
- GetStackClusterID(ctx context.Context, stack string) (string, error)
- GetStackMetadataClusterID(ctx context.Context, stack string) (string, error)
- GetServiceTaskDefinition(ctx context.Context, cluster string, serviceArns []string) (map[string]string, error)
- ListStackServices(ctx context.Context, stack string) ([]string, error)
- GetServiceTasks(ctx context.Context, cluster string, service string, stopped bool) ([]*ecs.Task, error)
- GetTaskStoppedReason(ctx context.Context, cluster string, taskArn string) (string, error)
- DescribeStackEvents(ctx context.Context, stackID string) ([]*cloudformation.StackEvent, error)
- ListStackParameters(ctx context.Context, name string) (map[string]string, error)
- ListStackResources(ctx context.Context, name string) (stackResources, error)
- DeleteStack(ctx context.Context, name string) error
- GetLogs(ctx context.Context, name string, consumer func(container string, service string, message string), follow bool) error
- DescribeService(ctx context.Context, cluster string, arn string) (api.ServiceStatus, error)
- DescribeServiceTasks(ctx context.Context, cluster string, project string, service string) ([]api.ContainerSummary, error)
- getURLWithPortMapping(ctx context.Context, targetGroupArns []string) ([]api.PortPublisher, error)
- ListTasks(ctx context.Context, cluster string, family string) ([]string, error)
- GetPublicIPs(ctx context.Context, interfaces ...string) (map[string]string, error)
- ResolveLoadBalancer(ctx context.Context, nameOrArn string) (awsResource, string, string, []awsResource, error)
- GetLoadBalancerURL(ctx context.Context, arn string) (string, error)
- GetParameter(ctx context.Context, name string) (string, error)
- SecurityGroupExists(ctx context.Context, sg string) (bool, error)
- DeleteCapacityProvider(ctx context.Context, arn string) error
- DeleteAutoscalingGroup(ctx context.Context, arn string) error
- ResolveFileSystem(ctx context.Context, id string) (awsResource, error)
- ListFileSystems(ctx context.Context, tags map[string]string) ([]awsResource, error)
- CreateFileSystem(ctx context.Context, tags map[string]string, options VolumeCreateOptions) (awsResource, error)
- DeleteFileSystem(ctx context.Context, id string) error
-}
diff --git a/ecs/awsResources.go b/ecs/awsResources.go
deleted file mode 100644
index f91bb1ee..00000000
--- a/ecs/awsResources.go
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
- "fmt"
- "strconv"
- "strings"
-
- "github.com/aws/aws-sdk-go/aws/arn"
- "github.com/aws/aws-sdk-go/service/elbv2"
- "github.com/awslabs/goformation/v4/cloudformation"
- "github.com/awslabs/goformation/v4/cloudformation/ec2"
- "github.com/awslabs/goformation/v4/cloudformation/ecs"
- "github.com/awslabs/goformation/v4/cloudformation/efs"
- "github.com/awslabs/goformation/v4/cloudformation/elasticloadbalancingv2"
- "github.com/compose-spec/compose-go/types"
- "github.com/docker/compose/v2/pkg/api"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// awsResources hold the AWS component being used or created to support services definition
-type awsResources struct {
- vpc string // shouldn't this also be an awsResource ?
- subnets []awsResource
- cluster awsResource
- loadBalancer awsResource
- loadBalancerType string
- securityGroups map[string]string
- filesystems map[string]awsResource
-}
-
-func (r *awsResources) serviceSecurityGroups(service types.ServiceConfig) []string {
- var groups []string
- for net := range service.Networks {
- groups = append(groups, r.securityGroups[net])
- }
- return groups
-}
-
-func (r *awsResources) allSecurityGroups() []string {
- var securityGroups []string
- for _, r := range r.securityGroups {
- securityGroups = append(securityGroups, r)
- }
- return securityGroups
-}
-
-func (r *awsResources) subnetsIDs() []string {
- var ids []string
- for _, r := range r.subnets {
- ids = append(ids, r.ID())
- }
- return ids
-}
-
-// awsResource is abstract representation for any (existing or future) AWS resource that we can refer both by ID or full ARN
-type awsResource interface {
- ARN() string
- ID() string
-}
-
-// existingAWSResource hold references to an existing AWS component
-type existingAWSResource struct {
- arn string
- id string
-}
-
-func (r existingAWSResource) ARN() string {
- return r.arn
-}
-
-func (r existingAWSResource) ID() string {
- return r.id
-}
-
-// cloudformationResource hold references to a future AWS resource managed by CloudFormation
-// to be used by CloudFormation resources where Ref returns the Amazon Resource ID
-type cloudformationResource struct {
- logicalName string
-}
-
-func (r cloudformationResource) ARN() string {
- return cloudformation.GetAtt(r.logicalName, "Arn")
-}
-
-func (r cloudformationResource) ID() string {
- return cloudformation.Ref(r.logicalName)
-}
-
-// cloudformationARNResource hold references to a future AWS resource managed by CloudFormation
-// to be used by CloudFormation resources where Ref returns the Amazon Resource Name (ARN)
-type cloudformationARNResource struct {
- logicalName string
- nameProperty string
-}
-
-func (r cloudformationARNResource) ARN() string {
- return cloudformation.Ref(r.logicalName)
-}
-
-func (r cloudformationARNResource) ID() string {
- return cloudformation.GetAtt(r.logicalName, r.nameProperty)
-}
-
-// parse look into compose project for configured resource to use, and check they are valid
-func (b *ComposeECS) parse(ctx context.Context, project *types.Project, template *cloudformation.Template) (awsResources, error) {
- r := awsResources{}
- var err error
- r.cluster, err = b.parseClusterExtension(ctx, project, template)
- if err != nil {
- return r, err
- }
- err = b.parseLoadBalancerExtension(ctx, project, &r)
- if err != nil {
- return r, err
- }
- err = b.parseVPCExtension(ctx, project, &r)
- if err != nil {
- return r, err
- }
- r.securityGroups, err = b.parseExternalNetworks(ctx, project)
- if err != nil {
- return r, err
- }
- r.filesystems, err = b.parseExternalVolumes(ctx, project)
- if err != nil {
- return r, err
- }
- return r, nil
-}
-
-func (b *ComposeECS) parseClusterExtension(ctx context.Context, project *types.Project, template *cloudformation.Template) (awsResource, error) {
- if x, ok := project.Extensions[extensionCluster]; ok {
- nameOrArn := x.(string) // can be name _or_ ARN.
- cluster, err := b.aws.ResolveCluster(ctx, nameOrArn)
- if err != nil {
- return nil, err
- }
- if !ok {
- return nil, errors.Wrapf(api.ErrNotFound, "cluster %q does not exist", cluster)
- }
-
- template.Metadata["Cluster"] = cluster.ARN()
- return cluster, nil
- }
- return nil, nil
-}
-
-func (b *ComposeECS) parseVPCExtension(ctx context.Context, project *types.Project, r *awsResources) error {
- var vpc string
- if x, ok := project.Extensions[extensionVPC]; ok {
- vpc = x.(string)
- ARN, err := arn.Parse(vpc)
- if err == nil {
- // User has set an ARN, like the one Terraform shows as output, while we expect an ID
- id := ARN.Resource
- i := strings.LastIndex(id, "/")
- vpc = id[i+1:]
- }
-
- if r.vpc != "" {
- if r.vpc != vpc {
- return fmt.Errorf("load balancer set by %s is attached to VPC %s", extensionLoadBalancer, r.vpc)
- }
- return nil
- }
-
- err = b.aws.CheckVPC(ctx, vpc)
- if err != nil {
- return err
- }
-
- } else {
- if r.vpc != "" {
- return nil
- }
-
- defaultVPC, err := b.aws.GetDefaultVPC(ctx)
- if err != nil {
- return err
- }
- vpc = defaultVPC
- }
-
- subNets, err := b.aws.GetSubNets(ctx, vpc)
- if err != nil {
- return err
- }
-
- var publicSubNets []awsResource
- for _, subNet := range subNets {
- isPublic, err := b.aws.IsPublicSubnet(ctx, subNet.ID())
- if err != nil {
- return err
- }
- if isPublic {
- publicSubNets = append(publicSubNets, subNet)
- }
- }
-
- if len(publicSubNets) < 2 {
- return fmt.Errorf("VPC %s should have at least 2 associated public subnets in different availability zones", vpc)
- }
-
- r.vpc = vpc
- r.subnets = subNets
- return nil
-}
-
-func (b *ComposeECS) parseLoadBalancerExtension(ctx context.Context, project *types.Project, r *awsResources) error {
- if x, ok := project.Extensions[extensionLoadBalancer]; ok {
- nameOrArn := x.(string)
- loadBalancer, loadBalancerType, vpc, subnets, err := b.aws.ResolveLoadBalancer(ctx, nameOrArn)
- if err != nil {
- return err
- }
-
- required := getRequiredLoadBalancerType(project)
- if loadBalancerType != required {
- return fmt.Errorf("load balancer %q is of type %s, project require a %s", nameOrArn, loadBalancerType, required)
- }
-
- r.loadBalancer = loadBalancer
- r.loadBalancerType = loadBalancerType
- r.vpc = vpc
- r.subnets = subnets
- return err
- }
- return nil
-}
-
-func (b *ComposeECS) parseExternalNetworks(ctx context.Context, project *types.Project) (map[string]string, error) {
- securityGroups := make(map[string]string, len(project.Networks))
- for name, net := range project.Networks {
- // FIXME remove this for G.A
- if x, ok := net.Extensions[extensionSecurityGroup]; ok {
- logrus.Warn("to use an existing security-group, use `network.external` and `network.name` in your compose file")
- logrus.Debugf("Security Group for network %q set by user to %q", net.Name, x)
- net.External.External = true
- net.Name = x.(string)
- project.Networks[name] = net
- }
-
- if !net.External.External {
- continue
- }
- exists, err := b.aws.SecurityGroupExists(ctx, net.Name)
- if err != nil {
- return nil, err
- }
- if !exists {
- return nil, errors.Wrapf(api.ErrNotFound, "security group %q doesn't exist", net.Name)
- }
- securityGroups[name] = net.Name
- }
- return securityGroups, nil
-}
-
-func (b *ComposeECS) parseExternalVolumes(ctx context.Context, project *types.Project) (map[string]awsResource, error) {
- filesystems := make(map[string]awsResource, len(project.Volumes))
- for name, vol := range project.Volumes {
- if vol.External.External {
- arn, err := b.aws.ResolveFileSystem(ctx, vol.Name)
- if err != nil {
- return nil, err
- }
- filesystems[name] = arn
- continue
- }
-
- logrus.Debugf("searching for existing filesystem as volume %q", name)
- tags := map[string]string{
- api.ProjectLabel: project.Name,
- api.VolumeLabel: name,
- }
- previous, err := b.aws.ListFileSystems(ctx, tags)
- if err != nil {
- return nil, err
- }
-
- if len(previous) > 1 {
- return nil, fmt.Errorf("multiple filesystems are tags as project=%q, volume=%q", project.Name, name)
- }
- if len(previous) == 1 {
- filesystems[name] = previous[0]
- }
- }
- return filesystems, nil
-}
-
-// ensureResources create required resources in template if not yet defined
-func (b *ComposeECS) ensureResources(resources *awsResources, project *types.Project, template *cloudformation.Template) error {
- b.ensureCluster(resources, project, template)
- b.ensureNetworks(resources, project, template)
- err := b.ensureVolumes(resources, project, template)
- if err != nil {
- return err
- }
- b.ensureLoadBalancer(resources, project, template)
- return nil
-}
-
-func (b *ComposeECS) ensureCluster(r *awsResources, project *types.Project, template *cloudformation.Template) {
- if r.cluster != nil {
- return
- }
- template.Resources["Cluster"] = &ecs.Cluster{
- ClusterName: project.Name,
- Tags: projectTags(project),
- }
- r.cluster = cloudformationResource{logicalName: "Cluster"}
-}
-
-func (b *ComposeECS) ensureNetworks(r *awsResources, project *types.Project, template *cloudformation.Template) {
- if r.securityGroups == nil {
- r.securityGroups = make(map[string]string, len(project.Networks))
- }
- for name, net := range project.Networks {
- if _, ok := r.securityGroups[name]; ok {
- continue
- }
- securityGroup := networkResourceName(name)
- template.Resources[securityGroup] = &ec2.SecurityGroup{
- GroupDescription: fmt.Sprintf("%s Security Group for %s network", project.Name, name),
- VpcId: r.vpc,
- Tags: networkTags(project, net),
- }
-
- ingress := securityGroup + "Ingress"
- template.Resources[ingress] = &ec2.SecurityGroupIngress{
- Description: fmt.Sprintf("Allow communication within network %s", name),
- IpProtocol: allProtocols,
- GroupId: cloudformation.Ref(securityGroup),
- SourceSecurityGroupId: cloudformation.Ref(securityGroup),
- }
-
- r.securityGroups[name] = cloudformation.Ref(securityGroup)
- }
-}
-
-func (b *ComposeECS) ensureVolumes(r *awsResources, project *types.Project, template *cloudformation.Template) error {
- for name, volume := range project.Volumes {
- if _, ok := r.filesystems[name]; ok {
- continue
- }
-
- var backupPolicy *efs.FileSystem_BackupPolicy
- if backup, ok := volume.DriverOpts["backup_policy"]; ok {
- backupPolicy = &efs.FileSystem_BackupPolicy{
- Status: backup,
- }
- }
-
- var lifecyclePolicies []efs.FileSystem_LifecyclePolicy
- if policy, ok := volume.DriverOpts["lifecycle_policy"]; ok {
- lifecyclePolicies = append(lifecyclePolicies, efs.FileSystem_LifecyclePolicy{
- TransitionToIA: strings.TrimSpace(policy),
- })
- }
-
- var provisionedThroughputInMibps float64
- if t, ok := volume.DriverOpts["provisioned_throughput"]; ok {
- v, err := strconv.ParseFloat(t, 64)
- if err != nil {
- return err
- }
- provisionedThroughputInMibps = v
- }
-
- var performanceMode = volume.DriverOpts["performance_mode"]
- var throughputMode = volume.DriverOpts["throughput_mode"]
- var kmsKeyID = volume.DriverOpts["kms_key_id"]
-
- n := volumeResourceName(name)
- template.Resources[n] = &efs.FileSystem{
- BackupPolicy: backupPolicy,
- Encrypted: true,
- FileSystemPolicy: nil,
- FileSystemTags: []efs.FileSystem_ElasticFileSystemTag{
- {
- Key: api.ProjectLabel,
- Value: project.Name,
- },
- {
- Key: api.VolumeLabel,
- Value: name,
- },
- {
- Key: "Name",
- Value: volume.Name,
- },
- },
- KmsKeyId: kmsKeyID,
- LifecyclePolicies: lifecyclePolicies,
- PerformanceMode: performanceMode,
- ProvisionedThroughputInMibps: provisionedThroughputInMibps,
- ThroughputMode: throughputMode,
- AWSCloudFormationDeletionPolicy: "Retain",
- }
- r.filesystems[name] = cloudformationResource{logicalName: n}
- }
- return nil
-}
-
-func (b *ComposeECS) ensureLoadBalancer(r *awsResources, project *types.Project, template *cloudformation.Template) {
- if r.loadBalancer != nil {
- return
- }
- if allServices(project.Services, func(it types.ServiceConfig) bool {
- return len(it.Ports) == 0
- }) {
- logrus.Debug("Application does not expose any public port, so no need for a LoadBalancer")
- return
- }
-
- balancerType := getRequiredLoadBalancerType(project)
- var securityGroups []string
- if balancerType == elbv2.LoadBalancerTypeEnumApplication {
- // see https://docs.aws.amazon.com/elasticloadbalancing/latest/network/target-group-register-targets.html#target-security-groups
- // Network Load Balancers do not have associated security groups
- securityGroups = r.getLoadBalancerSecurityGroups(project)
- }
-
- var loadBalancerAttributes []elasticloadbalancingv2.LoadBalancer_LoadBalancerAttribute
- if balancerType == elbv2.LoadBalancerTypeEnumNetwork {
- loadBalancerAttributes = append(
- loadBalancerAttributes,
- elasticloadbalancingv2.LoadBalancer_LoadBalancerAttribute{
- Key: "load_balancing.cross_zone.enabled",
- Value: "true",
- })
- }
-
- template.Resources["LoadBalancer"] = &elasticloadbalancingv2.LoadBalancer{
- Scheme: elbv2.LoadBalancerSchemeEnumInternetFacing,
- SecurityGroups: securityGroups,
- Subnets: r.subnetsIDs(),
- Tags: projectTags(project),
- Type: balancerType,
- LoadBalancerAttributes: loadBalancerAttributes,
- }
- r.loadBalancer = cloudformationARNResource{
- logicalName: "LoadBalancer",
- nameProperty: "LoadBalancerName",
- }
- r.loadBalancerType = balancerType
-}
-
-func (r *awsResources) getLoadBalancerSecurityGroups(project *types.Project) []string {
- securityGroups := []string{}
- for name, network := range project.Networks {
- if !network.Internal {
- securityGroups = append(securityGroups, r.securityGroups[name])
- }
- }
- return securityGroups
-}
-
-func getRequiredLoadBalancerType(project *types.Project) string {
- loadBalancerType := elbv2.LoadBalancerTypeEnumNetwork
- if allServices(project.Services, func(it types.ServiceConfig) bool {
- return allPorts(it.Ports, portIsHTTP)
- }) {
- loadBalancerType = elbv2.LoadBalancerTypeEnumApplication
- }
- return loadBalancerType
-}
-
-func portIsHTTP(it types.ServicePortConfig) bool {
- if v, ok := it.Extensions[extensionProtocol]; ok {
- protocol := v.(string)
- return protocol == "http" || protocol == "https"
- }
- return it.Target == 80 || it.Target == 443
-}
-
-// predicate[types.ServiceConfig]
-type servicePredicate func(it types.ServiceConfig) bool
-
-// all[types.ServiceConfig]
-func allServices(services types.Services, p servicePredicate) bool {
- for _, s := range services {
- if !p(s) {
- return false
- }
- }
- return true
-}
-
-// predicate[types.ServicePortConfig]
-type portPredicate func(it types.ServicePortConfig) bool
-
-// all[types.ServicePortConfig]
-func allPorts(ports []types.ServicePortConfig, p portPredicate) bool {
- for _, s := range ports {
- if !p(s) {
- return false
- }
- }
- return true
-}
diff --git a/ecs/aws_mock.go b/ecs/aws_mock.go
deleted file mode 100644
index 8b7671ae..00000000
--- a/ecs/aws_mock.go
+++ /dev/null
@@ -1,697 +0,0 @@
-// Code generated by MockGen. DO NOT EDIT.
-// Container: github.com/docker/compose-ecs/ecs (interfaces: API)
-
-// Package ecs is a generated GoMock package.
-package ecs
-
-import (
- context "context"
- reflect "reflect"
-
- cloudformation "github.com/aws/aws-sdk-go/service/cloudformation"
- ecs "github.com/aws/aws-sdk-go/service/ecs"
- compose "github.com/docker/compose/v2/pkg/api"
- gomock "github.com/golang/mock/gomock"
-
- secrets "github.com/docker/compose-ecs/api/secrets"
-)
-
-// MockAPI is a mock of API interface
-type MockAPI struct {
- ctrl *gomock.Controller
- recorder *MockAPIMockRecorder
-}
-
-// MockAPIMockRecorder is the mock recorder for MockAPI
-type MockAPIMockRecorder struct {
- mock *MockAPI
-}
-
-// NewMockAPI creates a new mock instance
-func NewMockAPI(ctrl *gomock.Controller) *MockAPI {
- mock := &MockAPI{ctrl: ctrl}
- mock.recorder = &MockAPIMockRecorder{mock}
- return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use
-func (m *MockAPI) EXPECT() *MockAPIMockRecorder {
- return m.recorder
-}
-
-// CheckRequirements mocks base method
-func (m *MockAPI) CheckRequirements(arg0 context.Context, arg1 string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "CheckRequirements", arg0, arg1)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// CheckRequirements indicates an expected call of CheckRequirements
-func (mr *MockAPIMockRecorder) CheckRequirements(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckRequirements", reflect.TypeOf((*MockAPI)(nil).CheckRequirements), arg0, arg1)
-}
-
-// CheckVPC mocks base method
-func (m *MockAPI) CheckVPC(arg0 context.Context, arg1 string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "CheckVPC", arg0, arg1)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// CheckVPC indicates an expected call of CheckVPC
-func (mr *MockAPIMockRecorder) CheckVPC(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckVPC", reflect.TypeOf((*MockAPI)(nil).CheckVPC), arg0, arg1)
-}
-
-// CreateChangeSet mocks base method
-func (m *MockAPI) CreateChangeSet(arg0 context.Context, arg1, arg2 string, arg3 []byte) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "CreateChangeSet", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// CreateChangeSet indicates an expected call of CreateChangeSet
-func (mr *MockAPIMockRecorder) CreateChangeSet(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateChangeSet", reflect.TypeOf((*MockAPI)(nil).CreateChangeSet), arg0, arg1, arg2, arg3)
-}
-
-// CreateCluster mocks base method
-func (m *MockAPI) CreateCluster(arg0 context.Context, arg1 string) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "CreateCluster", arg0, arg1)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// CreateCluster indicates an expected call of CreateCluster
-func (mr *MockAPIMockRecorder) CreateCluster(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCluster", reflect.TypeOf((*MockAPI)(nil).CreateCluster), arg0, arg1)
-}
-
-// CreateFileSystem mocks base method
-func (m *MockAPI) CreateFileSystem(arg0 context.Context, arg1 map[string]string, arg2 VolumeCreateOptions) (awsResource, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "CreateFileSystem", arg0, arg1, arg2)
- ret0, _ := ret[0].(awsResource)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// CreateFileSystem indicates an expected call of CreateFileSystem
-func (mr *MockAPIMockRecorder) CreateFileSystem(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFileSystem", reflect.TypeOf((*MockAPI)(nil).CreateFileSystem), arg0, arg1, arg2)
-}
-
-// CreateSecret mocks base method
-func (m *MockAPI) CreateSecret(arg0 context.Context, arg1 secrets.Secret) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "CreateSecret", arg0, arg1)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// CreateSecret indicates an expected call of CreateSecret
-func (mr *MockAPIMockRecorder) CreateSecret(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSecret", reflect.TypeOf((*MockAPI)(nil).CreateSecret), arg0, arg1)
-}
-
-// CreateStack mocks base method
-func (m *MockAPI) CreateStack(arg0 context.Context, arg1, arg2 string, arg3 []byte) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "CreateStack", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// CreateStack indicates an expected call of CreateStack
-func (mr *MockAPIMockRecorder) CreateStack(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateStack", reflect.TypeOf((*MockAPI)(nil).CreateStack), arg0, arg1, arg2, arg3)
-}
-
-// DeleteAutoscalingGroup mocks base method
-func (m *MockAPI) DeleteAutoscalingGroup(arg0 context.Context, arg1 string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DeleteAutoscalingGroup", arg0, arg1)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// DeleteAutoscalingGroup indicates an expected call of DeleteAutoscalingGroup
-func (mr *MockAPIMockRecorder) DeleteAutoscalingGroup(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAutoscalingGroup", reflect.TypeOf((*MockAPI)(nil).DeleteAutoscalingGroup), arg0, arg1)
-}
-
-// DeleteCapacityProvider mocks base method
-func (m *MockAPI) DeleteCapacityProvider(arg0 context.Context, arg1 string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DeleteCapacityProvider", arg0, arg1)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// DeleteCapacityProvider indicates an expected call of DeleteCapacityProvider
-func (mr *MockAPIMockRecorder) DeleteCapacityProvider(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteCapacityProvider", reflect.TypeOf((*MockAPI)(nil).DeleteCapacityProvider), arg0, arg1)
-}
-
-// DeleteFileSystem mocks base method
-func (m *MockAPI) DeleteFileSystem(arg0 context.Context, arg1 string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DeleteFileSystem", arg0, arg1)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// DeleteFileSystem indicates an expected call of DeleteFileSystem
-func (mr *MockAPIMockRecorder) DeleteFileSystem(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFileSystem", reflect.TypeOf((*MockAPI)(nil).DeleteFileSystem), arg0, arg1)
-}
-
-// DeleteSecret mocks base method
-func (m *MockAPI) DeleteSecret(arg0 context.Context, arg1 string, arg2 bool) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DeleteSecret", arg0, arg1, arg2)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// DeleteSecret indicates an expected call of DeleteSecret
-func (mr *MockAPIMockRecorder) DeleteSecret(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSecret", reflect.TypeOf((*MockAPI)(nil).DeleteSecret), arg0, arg1, arg2)
-}
-
-// DeleteStack mocks base method
-func (m *MockAPI) DeleteStack(arg0 context.Context, arg1 string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DeleteStack", arg0, arg1)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// DeleteStack indicates an expected call of DeleteStack
-func (mr *MockAPIMockRecorder) DeleteStack(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStack", reflect.TypeOf((*MockAPI)(nil).DeleteStack), arg0, arg1)
-}
-
-// DescribeService mocks base method
-func (m *MockAPI) DescribeService(arg0 context.Context, arg1, arg2 string) (compose.ServiceStatus, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DescribeService", arg0, arg1, arg2)
- ret0, _ := ret[0].(compose.ServiceStatus)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// DescribeService indicates an expected call of DescribeService
-func (mr *MockAPIMockRecorder) DescribeService(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeService", reflect.TypeOf((*MockAPI)(nil).DescribeService), arg0, arg1, arg2)
-}
-
-// DescribeServiceTasks mocks base method
-func (m *MockAPI) DescribeServiceTasks(arg0 context.Context, arg1, arg2, arg3 string) ([]compose.ContainerSummary, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DescribeServiceTasks", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].([]compose.ContainerSummary)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// DescribeServiceTasks indicates an expected call of DescribeServiceTasks
-func (mr *MockAPIMockRecorder) DescribeServiceTasks(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeServiceTasks", reflect.TypeOf((*MockAPI)(nil).DescribeServiceTasks), arg0, arg1, arg2, arg3)
-}
-
-// DescribeStackEvents mocks base method
-func (m *MockAPI) DescribeStackEvents(arg0 context.Context, arg1 string) ([]*cloudformation.StackEvent, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DescribeStackEvents", arg0, arg1)
- ret0, _ := ret[0].([]*cloudformation.StackEvent)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// DescribeStackEvents indicates an expected call of DescribeStackEvents
-func (mr *MockAPIMockRecorder) DescribeStackEvents(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackEvents", reflect.TypeOf((*MockAPI)(nil).DescribeStackEvents), arg0, arg1)
-}
-
-// GetDefaultVPC mocks base method
-func (m *MockAPI) GetDefaultVPC(arg0 context.Context) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetDefaultVPC", arg0)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetDefaultVPC indicates an expected call of GetDefaultVPC
-func (mr *MockAPIMockRecorder) GetDefaultVPC(arg0 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultVPC", reflect.TypeOf((*MockAPI)(nil).GetDefaultVPC), arg0)
-}
-
-// GetLoadBalancerURL mocks base method
-func (m *MockAPI) GetLoadBalancerURL(arg0 context.Context, arg1 string) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetLoadBalancerURL", arg0, arg1)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetLoadBalancerURL indicates an expected call of GetLoadBalancerURL
-func (mr *MockAPIMockRecorder) GetLoadBalancerURL(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLoadBalancerURL", reflect.TypeOf((*MockAPI)(nil).GetLoadBalancerURL), arg0, arg1)
-}
-
-// GetLogs mocks base method
-func (m *MockAPI) GetLogs(arg0 context.Context, arg1 string, arg2 func(string, string, string), arg3 bool) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetLogs", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// GetLogs indicates an expected call of GetLogs
-func (mr *MockAPIMockRecorder) GetLogs(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockAPI)(nil).GetLogs), arg0, arg1, arg2, arg3)
-}
-
-// GetParameter mocks base method
-func (m *MockAPI) GetParameter(arg0 context.Context, arg1 string) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetParameter", arg0, arg1)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetParameter indicates an expected call of GetParameter
-func (mr *MockAPIMockRecorder) GetParameter(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParameter", reflect.TypeOf((*MockAPI)(nil).GetParameter), arg0, arg1)
-}
-
-// GetPublicIPs mocks base method
-func (m *MockAPI) GetPublicIPs(arg0 context.Context, arg1 ...string) (map[string]string, error) {
- m.ctrl.T.Helper()
- varargs := []interface{}{arg0}
- for _, a := range arg1 {
- varargs = append(varargs, a)
- }
- ret := m.ctrl.Call(m, "GetPublicIPs", varargs...)
- ret0, _ := ret[0].(map[string]string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetPublicIPs indicates an expected call of GetPublicIPs
-func (mr *MockAPIMockRecorder) GetPublicIPs(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- varargs := append([]interface{}{arg0}, arg1...)
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublicIPs", reflect.TypeOf((*MockAPI)(nil).GetPublicIPs), varargs...)
-}
-
-// GetRoleArn mocks base method
-func (m *MockAPI) GetRoleArn(arg0 context.Context, arg1 string) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetRoleArn", arg0, arg1)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetRoleArn indicates an expected call of GetRoleArn
-func (mr *MockAPIMockRecorder) GetRoleArn(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRoleArn", reflect.TypeOf((*MockAPI)(nil).GetRoleArn), arg0, arg1)
-}
-
-// GetServiceTaskDefinition mocks base method
-func (m *MockAPI) GetServiceTaskDefinition(arg0 context.Context, arg1 string, arg2 []string) (map[string]string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetServiceTaskDefinition", arg0, arg1, arg2)
- ret0, _ := ret[0].(map[string]string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetServiceTaskDefinition indicates an expected call of GetServiceTaskDefinition
-func (mr *MockAPIMockRecorder) GetServiceTaskDefinition(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceTaskDefinition", reflect.TypeOf((*MockAPI)(nil).GetServiceTaskDefinition), arg0, arg1, arg2)
-}
-
-// GetServiceTasks mocks base method
-func (m *MockAPI) GetServiceTasks(arg0 context.Context, arg1, arg2 string, arg3 bool) ([]*ecs.Task, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetServiceTasks", arg0, arg1, arg2, arg3)
- ret0, _ := ret[0].([]*ecs.Task)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetServiceTasks indicates an expected call of GetServiceTasks
-func (mr *MockAPIMockRecorder) GetServiceTasks(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceTasks", reflect.TypeOf((*MockAPI)(nil).GetServiceTasks), arg0, arg1, arg2, arg3)
-}
-
-// GetStackClusterID mocks base method
-func (m *MockAPI) GetStackClusterID(arg0 context.Context, arg1 string) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetStackClusterID", arg0, arg1)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetStackClusterID indicates an expected call of GetStackClusterID
-func (mr *MockAPIMockRecorder) GetStackClusterID(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStackClusterID", reflect.TypeOf((*MockAPI)(nil).GetStackClusterID), arg0, arg1)
-}
-
-// GetStackID mocks base method
-func (m *MockAPI) GetStackID(arg0 context.Context, arg1 string) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetStackID", arg0, arg1)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetStackID indicates an expected call of GetStackID
-func (mr *MockAPIMockRecorder) GetStackID(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStackID", reflect.TypeOf((*MockAPI)(nil).GetStackID), arg0, arg1)
-}
-
-// GetSubNets mocks base method
-func (m *MockAPI) GetSubNets(arg0 context.Context, arg1 string) ([]awsResource, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetSubNets", arg0, arg1)
- ret0, _ := ret[0].([]awsResource)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetSubNets indicates an expected call of GetSubNets
-func (mr *MockAPIMockRecorder) GetSubNets(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubNets", reflect.TypeOf((*MockAPI)(nil).GetSubNets), arg0, arg1)
-}
-
-// GetTaskStoppedReason mocks base method
-func (m *MockAPI) GetTaskStoppedReason(arg0 context.Context, arg1, arg2 string) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetTaskStoppedReason", arg0, arg1, arg2)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetTaskStoppedReason indicates an expected call of GetTaskStoppedReason
-func (mr *MockAPIMockRecorder) GetTaskStoppedReason(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTaskStoppedReason", reflect.TypeOf((*MockAPI)(nil).GetTaskStoppedReason), arg0, arg1, arg2)
-}
-
-// InspectSecret mocks base method
-func (m *MockAPI) InspectSecret(arg0 context.Context, arg1 string) (secrets.Secret, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "InspectSecret", arg0, arg1)
- ret0, _ := ret[0].(secrets.Secret)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// InspectSecret indicates an expected call of InspectSecret
-func (mr *MockAPIMockRecorder) InspectSecret(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InspectSecret", reflect.TypeOf((*MockAPI)(nil).InspectSecret), arg0, arg1)
-}
-
-// IsPublicSubnet mocks base method
-func (m *MockAPI) IsPublicSubnet(arg0 context.Context, arg1 string) (bool, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "IsPublicSubnet", arg0, arg1)
- ret0, _ := ret[0].(bool)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// IsPublicSubnet indicates an expected call of IsPublicSubnet
-func (mr *MockAPIMockRecorder) IsPublicSubnet(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsPublicSubnet", reflect.TypeOf((*MockAPI)(nil).IsPublicSubnet), arg0, arg1)
-}
-
-// ListFileSystems mocks base method
-func (m *MockAPI) ListFileSystems(arg0 context.Context, arg1 map[string]string) ([]awsResource, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListFileSystems", arg0, arg1)
- ret0, _ := ret[0].([]awsResource)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ListFileSystems indicates an expected call of ListFileSystems
-func (mr *MockAPIMockRecorder) ListFileSystems(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListFileSystems", reflect.TypeOf((*MockAPI)(nil).ListFileSystems), arg0, arg1)
-}
-
-// ListSecrets mocks base method
-func (m *MockAPI) ListSecrets(arg0 context.Context) ([]secrets.Secret, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListSecrets", arg0)
- ret0, _ := ret[0].([]secrets.Secret)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ListSecrets indicates an expected call of ListSecrets
-func (mr *MockAPIMockRecorder) ListSecrets(arg0 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSecrets", reflect.TypeOf((*MockAPI)(nil).ListSecrets), arg0)
-}
-
-// ListStackParameters mocks base method
-func (m *MockAPI) ListStackParameters(arg0 context.Context, arg1 string) (map[string]string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListStackParameters", arg0, arg1)
- ret0, _ := ret[0].(map[string]string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ListStackParameters indicates an expected call of ListStackParameters
-func (mr *MockAPIMockRecorder) ListStackParameters(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStackParameters", reflect.TypeOf((*MockAPI)(nil).ListStackParameters), arg0, arg1)
-}
-
-// ListStackResources mocks base method
-func (m *MockAPI) ListStackResources(arg0 context.Context, arg1 string) (stackResources, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListStackResources", arg0, arg1)
- ret0, _ := ret[0].(stackResources)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ListStackResources indicates an expected call of ListStackResources
-func (mr *MockAPIMockRecorder) ListStackResources(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStackResources", reflect.TypeOf((*MockAPI)(nil).ListStackResources), arg0, arg1)
-}
-
-// ListStackServices mocks base method
-func (m *MockAPI) ListStackServices(arg0 context.Context, arg1 string) ([]string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListStackServices", arg0, arg1)
- ret0, _ := ret[0].([]string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ListStackServices indicates an expected call of ListStackServices
-func (mr *MockAPIMockRecorder) ListStackServices(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStackServices", reflect.TypeOf((*MockAPI)(nil).ListStackServices), arg0, arg1)
-}
-
-// ListStacks mocks base method
-func (m *MockAPI) ListStacks(arg0 context.Context) ([]compose.Stack, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListStacks", arg0)
- ret0, _ := ret[0].([]compose.Stack)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ListStacks indicates an expected call of ListStacks
-func (mr *MockAPIMockRecorder) ListStacks(arg0 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStacks", reflect.TypeOf((*MockAPI)(nil).ListStacks), arg0)
-}
-
-// ListTasks mocks base method
-func (m *MockAPI) ListTasks(arg0 context.Context, arg1, arg2 string) ([]string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ListTasks", arg0, arg1, arg2)
- ret0, _ := ret[0].([]string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ListTasks indicates an expected call of ListTasks
-func (mr *MockAPIMockRecorder) ListTasks(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTasks", reflect.TypeOf((*MockAPI)(nil).ListTasks), arg0, arg1, arg2)
-}
-
-// ResolveCluster mocks base method
-func (m *MockAPI) ResolveCluster(arg0 context.Context, arg1 string) (awsResource, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ResolveCluster", arg0, arg1)
- ret0, _ := ret[0].(awsResource)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ResolveCluster indicates an expected call of ResolveCluster
-func (mr *MockAPIMockRecorder) ResolveCluster(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveCluster", reflect.TypeOf((*MockAPI)(nil).ResolveCluster), arg0, arg1)
-}
-
-// ResolveFileSystem mocks base method
-func (m *MockAPI) ResolveFileSystem(arg0 context.Context, arg1 string) (awsResource, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ResolveFileSystem", arg0, arg1)
- ret0, _ := ret[0].(awsResource)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ResolveFileSystem indicates an expected call of ResolveFileSystem
-func (mr *MockAPIMockRecorder) ResolveFileSystem(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveFileSystem", reflect.TypeOf((*MockAPI)(nil).ResolveFileSystem), arg0, arg1)
-}
-
-// ResolveLoadBalancer mocks base method
-func (m *MockAPI) ResolveLoadBalancer(arg0 context.Context, arg1 string) (awsResource, string, string, []awsResource, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ResolveLoadBalancer", arg0, arg1)
- ret0, _ := ret[0].(awsResource)
- ret1, _ := ret[1].(string)
- ret2, _ := ret[2].(string)
- ret3, _ := ret[3].([]awsResource)
- ret4, _ := ret[4].(error)
- return ret0, ret1, ret2, ret3, ret4
-}
-
-// ResolveLoadBalancer indicates an expected call of ResolveLoadBalancer
-func (mr *MockAPIMockRecorder) ResolveLoadBalancer(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveLoadBalancer", reflect.TypeOf((*MockAPI)(nil).ResolveLoadBalancer), arg0, arg1)
-}
-
-// SecurityGroupExists mocks base method
-func (m *MockAPI) SecurityGroupExists(arg0 context.Context, arg1 string) (bool, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "SecurityGroupExists", arg0, arg1)
- ret0, _ := ret[0].(bool)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// SecurityGroupExists indicates an expected call of SecurityGroupExists
-func (mr *MockAPIMockRecorder) SecurityGroupExists(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SecurityGroupExists", reflect.TypeOf((*MockAPI)(nil).SecurityGroupExists), arg0, arg1)
-}
-
-// StackExists mocks base method
-func (m *MockAPI) StackExists(arg0 context.Context, arg1 string) (bool, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "StackExists", arg0, arg1)
- ret0, _ := ret[0].(bool)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// StackExists indicates an expected call of StackExists
-func (mr *MockAPIMockRecorder) StackExists(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StackExists", reflect.TypeOf((*MockAPI)(nil).StackExists), arg0, arg1)
-}
-
-// UpdateStack mocks base method
-func (m *MockAPI) UpdateStack(arg0 context.Context, arg1 string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "UpdateStack", arg0, arg1)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// UpdateStack indicates an expected call of UpdateStack
-func (mr *MockAPIMockRecorder) UpdateStack(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStack", reflect.TypeOf((*MockAPI)(nil).UpdateStack), arg0, arg1)
-}
-
-// WaitStackComplete mocks base method
-func (m *MockAPI) WaitStackComplete(arg0 context.Context, arg1 string, arg2 int) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "WaitStackComplete", arg0, arg1, arg2)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// WaitStackComplete indicates an expected call of WaitStackComplete
-func (mr *MockAPIMockRecorder) WaitStackComplete(arg0, arg1, arg2 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitStackComplete", reflect.TypeOf((*MockAPI)(nil).WaitStackComplete), arg0, arg1, arg2)
-}
-
-// getURLWithPortMapping mocks base method
-func (m *MockAPI) getURLWithPortMapping(arg0 context.Context, arg1 []string) ([]compose.PortPublisher, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "getURLWithPortMapping", arg0, arg1)
- ret0, _ := ret[0].([]compose.PortPublisher)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// getURLWithPortMapping indicates an expected call of getURLWithPortMapping
-func (mr *MockAPIMockRecorder) getURLWithPortMapping(arg0, arg1 interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "getURLWithPortMapping", reflect.TypeOf((*MockAPI)(nil).getURLWithPortMapping), arg0, arg1)
-}
diff --git a/ecs/backend.go b/ecs/backend.go
deleted file mode 100644
index 22042344..00000000
--- a/ecs/backend.go
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
- "github.com/compose-spec/compose-go/v2/types"
- "os"
-
- "github.com/aws/aws-sdk-go/aws/session"
- "github.com/docker/compose/v2/pkg/api"
-)
-
-func NewComposeECS() (*ComposeECS, error) {
- sess, err := session.NewSessionWithOptions(session.Options{
- SharedConfigState: session.SharedConfigEnable,
- Profile: os.Getenv("AWS_PROFILE"),
- })
- if err != nil {
- return nil, err
- }
-
- sdk := newSDK(sess)
- return &ComposeECS{
- Region: *sess.Config.Region,
- aws: sdk,
- }, nil
-}
-
-type ComposeECS struct {
- Region string
- aws API
-}
-
-func (b *ComposeECS) Build(ctx context.Context, project *types.Project, options api.BuildOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Push(ctx context.Context, project *types.Project, options api.PushOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Pull(ctx context.Context, project *types.Project, options api.PullOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Create(ctx context.Context, project *types.Project, options api.CreateOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Start(ctx context.Context, projectName string, options api.StartOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Restart(ctx context.Context, projectName string, options api.RestartOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Stop(ctx context.Context, projectName string, options api.StopOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Up(ctx context.Context, project *types.Project, options api.UpOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Config(ctx context.Context, project *types.Project, options api.ConfigOptions) ([]byte, error) {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Kill(ctx context.Context, projectName string, options api.KillOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) RunOneOffContainer(ctx context.Context, project *types.Project, opts api.RunOptions) (int, error) {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Remove(ctx context.Context, projectName string, options api.RemoveOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Attach(ctx context.Context, projectName string, options api.AttachOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Copy(ctx context.Context, projectName string, options api.CopyOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Port(ctx context.Context, projectName string, service string, port uint16, options api.PortOptions) (string, int, error) {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Publish(ctx context.Context, project *types.Project, repository string, options api.PublishOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) MaxConcurrency(parallel int) {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) DryRunMode(ctx context.Context, dryRun bool) (context.Context, error) {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Watch(ctx context.Context, project *types.Project, services []string, options api.WatchOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Viz(ctx context.Context, project *types.Project, options api.VizOptions) (string, error) {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Wait(ctx context.Context, projectName string, options api.WaitOptions) (int64, error) {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) Scale(ctx context.Context, project *types.Project, options api.ScaleOptions) error {
- //TODO implement me
- panic("implement me")
-}
-
-func (b *ComposeECS) ComposeService() api.Service {
- return b
-}
diff --git a/ecs/cloudformation.go b/ecs/cloudformation.go
index 7c654995..7509c771 100644
--- a/ecs/cloudformation.go
+++ b/ecs/cloudformation.go
@@ -1,548 +1,781 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
import (
- "context"
+ "encoding/json"
"fmt"
- "os"
"regexp"
+ "sort"
+ "strconv"
"strings"
+ "time"
- ecsapi "github.com/aws/aws-sdk-go/service/ecs"
- "github.com/aws/aws-sdk-go/service/elbv2"
- cloudmapapi "github.com/aws/aws-sdk-go/service/servicediscovery"
"github.com/awslabs/goformation/v4/cloudformation"
+ "github.com/awslabs/goformation/v4/cloudformation/applicationautoscaling"
"github.com/awslabs/goformation/v4/cloudformation/ec2"
"github.com/awslabs/goformation/v4/cloudformation/ecs"
"github.com/awslabs/goformation/v4/cloudformation/elasticloadbalancingv2"
"github.com/awslabs/goformation/v4/cloudformation/iam"
"github.com/awslabs/goformation/v4/cloudformation/logs"
- "github.com/awslabs/goformation/v4/cloudformation/secretsmanager"
- cloudmap "github.com/awslabs/goformation/v4/cloudformation/servicediscovery"
- "github.com/cnabio/cnab-to-oci/remotes"
- "github.com/compose-spec/compose-go/types"
- "github.com/distribution/distribution/v3/reference"
- cliconfig "github.com/docker/cli/cli/config"
+ "github.com/awslabs/goformation/v4/cloudformation/servicediscovery"
+ "github.com/awslabs/goformation/v4/cloudformation/tags"
+ "github.com/compose-spec/compose-go/v2/types"
+ "github.com/docker/cli/opts"
"github.com/docker/compose/v2/pkg/api"
- "github.com/opencontainers/go-digest"
- "sigs.k8s.io/kustomize/kyaml/yaml"
- "sigs.k8s.io/kustomize/kyaml/yaml/merge2"
-
- "github.com/docker/compose-ecs/utils"
+ "golang.org/x/text/cases"
+ "golang.org/x/text/language"
)
-func (b *ComposeECS) Convert(ctx context.Context, project *types.Project, options api.ConvertOptions) ([]byte, error) {
- if err := checkUnsupportedConvertOptions(ctx, options); err != nil {
- return nil, err
- }
- err := b.resolveServiceImagesDigests(ctx, project)
- if err != nil {
- return nil, err
- }
+const (
+ extensionAutoScaling = "x-aws-autoscaling"
+ extensionCloudFormation = "x-aws-cloudformation"
+ extensionLoadBalancer = "x-aws-loadbalancer"
+ extensionPullCredentials = "x-aws-pull_credentials"
+ extensionRole = "x-aws-role"
+ extensionSubnets = "x-aws-subnets"
+ extensionVpc = "x-aws-vpc"
+)
- template, err := b.convert(ctx, project)
- if err != nil {
- return nil, err
- }
+type resources struct {
+ loadBalancer string
+ securityGroups map[string]string
+ subnets []string
+ vpc string // shouldn't this also be an awsResource ?
+}
- bytes, err := marshall(template, options.Format)
- if err != nil {
- return nil, err
+func checkCompatibility(project *types.Project) error {
+ for _, config := range project.Configs {
+ return fmt.Errorf("configs are not supported: %s", config.Name)
}
- x, ok := project.Extensions[extensionCloudFormation]
- if !ok {
- return bytes, nil
- }
- if options.Format != "yaml" {
- return nil, fmt.Errorf("format %q with overlays is not supported", options.Format)
- }
-
- nodes, err := yaml.Parse(string(bytes))
- if err != nil {
- return nil, err
- }
+ for _, network := range project.Networks {
+ if strings.HasSuffix(network.Name, "_default") {
+ continue
+ }
- bytes, err = yaml.Marshal(x)
- if err != nil {
- return nil, err
- }
- overlay, err := yaml.Parse(string(bytes))
- if err != nil {
- return nil, err
- }
- nodes, err = merge2.Merge(overlay, nodes, yaml.MergeOptions{
- ListIncreaseDirection: yaml.MergeOptionsListPrepend,
- })
- if err != nil {
- return nil, err
+ if !network.External {
+ return fmt.Errorf("only external networks are supported: %s", network.Name)
+ }
}
- s, err := nodes.String()
- if err != nil {
- return nil, err
+ for _, secret := range project.Secrets {
+ if !secret.External {
+ return fmt.Errorf("only external secrets are supported: %s", secret.Name)
+ }
}
- bytes = []byte(s)
- return bytes, err
-}
-func checkUnsupportedConvertOptions(ctx context.Context, o api.ConvertOptions) error {
- return utils.CheckUnsupported(ctx, nil, o.Output, "", "convert", "output")
-}
+ // TODO: bring back some level of compatibility validation
+ //for _, service := range project.Services {
+ //}
-func (b *ComposeECS) resolveServiceImagesDigests(ctx context.Context, project *types.Project) error {
- configFile, err := cliconfig.Load(cliconfig.Dir())
- if err != nil {
- return err
+ for _, volume := range project.Volumes {
+ return fmt.Errorf("volumes are not supported: %s", volume.Name)
}
- resolver := remotes.CreateResolver(configFile)
- return project.ResolveImages(func(named reference.Named) (digest.Digest, error) {
- _, desc, err := resolver.Resolve(ctx, named.String())
- return desc.Digest, err
- })
+ return nil
}
-func (b *ComposeECS) convert(ctx context.Context, project *types.Project) (*cloudformation.Template, error) {
- err := b.checkCompatibility(project)
- if err != nil {
+func convert(project *types.Project) (*cloudformation.Template, error) {
+ if err := checkCompatibility(project); err != nil {
return nil, err
}
+ resources := resources{}
template := cloudformation.NewTemplate()
- resources, err := b.parse(ctx, project, template)
- if err != nil {
- return nil, err
- }
- err = b.ensureResources(&resources, project, template)
- if err != nil {
- return nil, err
+ if x, ok := project.Extensions[extensionLoadBalancer]; ok {
+ resources.loadBalancer = x.(string)
+ } else {
+ return nil, fmt.Errorf("missing required %s", extensionLoadBalancer)
}
- for name, secret := range project.Secrets {
- err := b.createSecret(project, name, secret, template)
- if err != nil {
- return nil, err
+ if x, ok := project.Extensions[extensionSubnets]; ok {
+ for _, subnet := range x.([]interface{}) {
+ resources.subnets = append(resources.subnets, subnet.(string))
}
+ } else {
+ return nil, fmt.Errorf("missing required %s", extensionSubnets)
}
- b.createLogGroup(project, template)
-
- // Private DNS namespace will allow DNS name for the services to be ..local
- b.createCloudMap(project, template, resources.vpc)
-
- b.createNFSMountTarget(project, resources, template)
+ if x, ok := project.Extensions[extensionVpc]; ok {
+ resources.vpc = x.(string)
+ } else {
+ return nil, fmt.Errorf("missing required %s", extensionVpc)
+ }
- b.createAccessPoints(project, resources, template)
+ template.Resources["CloudMap"] = &servicediscovery.PrivateDnsNamespace{
+ Description: fmt.Sprintf("Service Map for Docker Compose project %s", project.Name),
+ Name: fmt.Sprintf("%s.local", project.Name),
+ Tags: projectTags(project),
+ Vpc: resources.vpc,
+ }
+ template.Resources["Cluster"] = &ecs.Cluster{
+ ClusterName: project.Name,
+ Tags: projectTags(project),
+ }
+ template.Resources["LogGroup"] = &logs.LogGroup{
+ LogGroupName: fmt.Sprintf("/docker-compose/%s", project.Name),
+ RetentionInDays: 0,
+ }
for _, service := range project.Services {
- err := b.createService(project, service, template, resources)
- if err != nil {
+ if err := createService(project, service, template, resources); err != nil {
return nil, err
}
-
- err = b.createAutoscalingPolicy(project, resources, template, service)
- if err != nil {
- return nil, err
- }
- }
-
- err = b.createCapacityProvider(ctx, project, template, resources)
- if err != nil {
- return nil, err
}
return template, nil
}
-func (b *ComposeECS) createService(project *types.Project, service types.ServiceConfig, template *cloudformation.Template, resources awsResources) error {
- taskExecutionRole := b.createTaskExecutionRole(project, service, template)
- taskRole, err := b.createTaskRole(project, service, template, resources)
+func createAutoscalingPolicy(project *types.Project, template *cloudformation.Template, service types.ServiceConfig) error {
+ if service.Deploy == nil {
+ return nil
+ }
+ v, ok := service.Deploy.Extensions[extensionAutoScaling]
+ if !ok {
+ return nil
+ }
+
+ marshalled, err := json.Marshal(v)
if err != nil {
return err
}
- definition, err := b.createTaskDefinition(project, service, resources)
+ config := struct {
+ Memory int `json:"memory,omitempty"`
+ CPU int `json:"cpu,omitempty"`
+ Min int `json:"min,omitempty"`
+ Max int `json:"max,omitempty"`
+ }{}
+
+ err = json.Unmarshal(marshalled, &config)
if err != nil {
return err
}
- definition.ExecutionRoleArn = cloudformation.Ref(taskExecutionRole)
- if taskRole != "" {
- definition.TaskRoleArn = cloudformation.Ref(taskRole)
+
+ if config.Memory != 0 && config.CPU != 0 {
+ return fmt.Errorf("%s can't be set with both cpu and memory targets", extensionAutoScaling)
+ }
+ if config.Max == 0 {
+ return fmt.Errorf("%s MUST define max replicas", extensionAutoScaling)
}
- taskDefinition := fmt.Sprintf("%sTaskDefinition", normalizeResourceName(service.Name))
- template.Resources[taskDefinition] = definition
+ template.Resources[serviceAutoScalingRoleName(service)] = &iam.Role{
+ AssumeRolePolicyDocument: map[string]interface{}{
+ "Version": "2012-10-17",
+ "Statement": []map[string]interface{}{
+ {
+ "Action": []string{"sts:AssumeRole"},
+ "Effect": "Allow",
+ "Principal": map[string]interface{}{
+ "Service": "application-autoscaling.amazonaws.com",
+ },
+ },
+ },
+ },
+ Path: "/",
+ Policies: []iam.Role_Policy{
+ {
+ PolicyDocument: map[string]interface{}{
+ "Statement": []map[string]interface{}{
+ {
+ "Action": []string{
+ "application-autoscaling:*",
+ "cloudwatch:GetMetricStatistics",
+ "ecs:DescribeServices",
+ "ecs:UpdateService",
+ },
+ "Effect": "Allow",
+ "Resource": []string{cloudformation.Ref(serviceName(service))},
+ },
+ },
+ },
+ PolicyName: "service-autoscaling",
+ },
+ },
+ Tags: serviceTags(project, service),
+ }
+ template.Resources[serviceScalableTargetName(service)] = &applicationautoscaling.ScalableTarget{
+ MaxCapacity: config.Max,
+ MinCapacity: config.Min,
+ ResourceId: fmt.Sprintf("service/%s/%s", cloudformation.Ref("Cluster"), cloudformation.GetAtt(serviceName(service), "Name")),
+ RoleARN: cloudformation.GetAtt(serviceAutoScalingRoleName(service), "Arn"),
+ ScalableDimension: "ecs:service:DesiredCount",
+ ServiceNamespace: "ecs",
+ AWSCloudFormationDependsOn: []string{serviceName(service)},
+ }
- var healthCheck *cloudmap.Service_HealthCheckConfig
- serviceRegistry := b.createServiceRegistry(service, template, healthCheck)
+ metric := "ECSServiceAverageCPUUtilization"
+ targetPercent := config.CPU
- var (
- dependsOn []string
- serviceLB []ecs.Service_LoadBalancer
- )
- for _, port := range service.Ports {
- for net := range service.Networks {
- b.createIngress(service, net, port, template, resources)
- }
-
- protocol := strings.ToUpper(port.Protocol)
- if resources.loadBalancerType == elbv2.LoadBalancerTypeEnumApplication {
- // we don't set Https as a certificate must be specified for HTTPS listeners
- protocol = elbv2.ProtocolEnumHttp
- }
- targetGroupName := b.createTargetGroup(project, service, port, template, protocol, resources.vpc)
- listenerName := b.createListener(service, port, template, targetGroupName, resources.loadBalancer, protocol)
- dependsOn = append(dependsOn, listenerName)
- serviceLB = append(serviceLB, ecs.Service_LoadBalancer{
- ContainerName: service.Name,
- ContainerPort: int(port.Target),
- TargetGroupArn: cloudformation.Ref(targetGroupName),
- })
+ if config.Memory != 0 {
+ metric = "ECSServiceAverageMemoryUtilization"
+ targetPercent = config.Memory
}
- desiredCount := 1
- if service.Deploy != nil && service.Deploy.Replicas != nil {
- desiredCount = int(*service.Deploy.Replicas)
+ template.Resources[serviceScalingPolicyName(service)] = &applicationautoscaling.ScalingPolicy{
+ PolicyType: "TargetTrackingScaling",
+ PolicyName: serviceScalingPolicyName(service),
+ ScalingTargetId: cloudformation.Ref(serviceScalableTargetName(service)),
+ StepScalingPolicyConfiguration: nil,
+ TargetTrackingScalingPolicyConfiguration: &applicationautoscaling.ScalingPolicy_TargetTrackingScalingPolicyConfiguration{
+ PredefinedMetricSpecification: &applicationautoscaling.ScalingPolicy_PredefinedMetricSpecification{
+ PredefinedMetricType: metric,
+ },
+ ScaleOutCooldown: 60,
+ ScaleInCooldown: 60,
+ TargetValue: float64(targetPercent),
+ },
}
+ return nil
+}
- for dependency := range service.DependsOn {
- dependsOn = append(dependsOn, serviceResourceName(dependency))
+func createService(project *types.Project, service types.ServiceConfig, template *cloudformation.Template, resources resources) error {
+ var secretArns []string
+ if value, ok := service.Extensions[extensionPullCredentials]; ok {
+ secretArns = append(secretArns, value.(string))
}
-
- for _, s := range service.Volumes {
- dependsOn = append(dependsOn, b.mountTargets(s.Source, resources)...)
+ for _, secret := range service.Secrets {
+ secretArns = append(secretArns, project.Secrets[secret.Source].Name)
}
- minPercent, maxPercent, err := computeRollingUpdateLimits(service)
+ cpu, mem, err := toLimits(service)
if err != nil {
- return err
+ panic(err)
+ }
+
+ template.Resources[serviceDiscoveryEntryName(service)] = &servicediscovery.Service{
+ Description: fmt.Sprintf("%q service discovery entry in Cloud Map", service.Name),
+ HealthCheckConfig: nil,
+ HealthCheckCustomConfig: &servicediscovery.Service_HealthCheckCustomConfig{
+ FailureThreshold: 1,
+ },
+ Name: service.Name,
+ NamespaceId: cloudformation.Ref("CloudMap"),
+ DnsConfig: &servicediscovery.Service_DnsConfig{
+ DnsRecords: []servicediscovery.Service_DnsRecord{
+ {
+ TTL: 60,
+ Type: "A",
+ },
+ },
+ RoutingPolicy: "MULTIVALUE",
+ },
+ }
+ template.Resources[serviceTaskDefinitionName(service)] = &ecs.TaskDefinition{
+ ContainerDefinitions: []ecs.TaskDefinition_ContainerDefinition{
+ {
+ Command: service.Command,
+ DisableNetworking: false,
+ DependsOnProp: nil,
+ DnsSearchDomains: service.DNSSearch,
+ DnsServers: service.DNS,
+ DockerLabels: service.Labels,
+ DockerSecurityOptions: service.SecurityOpt,
+ EntryPoint: service.Entrypoint,
+ Environment: createEnvironment(service),
+ Essential: true,
+ ExtraHosts: nil,
+ FirelensConfiguration: nil,
+ HealthCheck: toHealthCheck(service.HealthCheck),
+ Hostname: service.Hostname,
+ Image: service.Image,
+ Interactive: false,
+ Links: nil,
+ LinuxParameters: nil,
+ LogConfiguration: &ecs.TaskDefinition_LogConfiguration{
+ LogDriver: "awslogs",
+ Options: map[string]string{
+ "awslogs-region": cloudformation.Ref("AWS::Region"),
+ "awslogs-group": cloudformation.Ref("LogGroup"),
+ "awslogs-stream-prefix": project.Name,
+ },
+ },
+ MemoryReservation: 0,
+ MountPoints: nil,
+ Name: service.Name,
+ PortMappings: toPortMappings(service.Ports),
+ Privileged: service.Privileged,
+ PseudoTerminal: service.Tty,
+ ReadonlyRootFilesystem: service.ReadOnly,
+ RepositoryCredentials: createRepositoryCredentials(service),
+ ResourceRequirements: nil,
+ Secrets: createTaskSecrets(project, service),
+ StartTimeout: 0,
+ StopTimeout: durationToInt(service.StopGracePeriod),
+ SystemControls: nil,
+ Ulimits: toUlimits(service.Ulimits),
+ User: service.User,
+ VolumesFrom: nil,
+ WorkingDirectory: service.WorkingDir,
+ },
+ },
+ Cpu: cpu,
+ ExecutionRoleArn: cloudformation.Ref(serviceTaskExecutionRoleName(service)),
+ Family: fmt.Sprintf("%s-%s", project.Name, service.Name),
+ IpcMode: service.Ipc,
+ Memory: mem,
+ NetworkMode: "awsvpc",
+ PidMode: service.Pid,
+ PlacementConstraints: nil,
+ ProxyConfiguration: nil,
+ RequiresCompatibilities: []string{"FARGATE"},
+ TaskRoleArn: cloudformation.Ref(fmt.Sprintf("%sTaskRole", normalizeResourceName(service.Name))),
+ Volumes: nil,
+ }
+ template.Resources[serviceTaskExecutionRoleName(service)] = &iam.Role{
+ AssumeRolePolicyDocument: map[string]interface{}{
+ "Version": "2012-10-17",
+ "Statement": []map[string]interface{}{
+ {
+ "Action": []string{"sts:AssumeRole"},
+ "Effect": "Allow",
+ "Principal": map[string]interface{}{
+ "Service": "ecs-tasks.amazonaws.com",
+ },
+ },
+ },
+ },
+ ManagedPolicyArns: []string{"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"},
+ Policies: []iam.Role_Policy{
+ {
+ PolicyDocument: map[string]interface{}{
+ "Statement": []map[string]interface{}{
+ {
+ "Action": []string{"secretsmanager:GetSecretValue"},
+ "Effect": "Allow",
+ "Resource": getSecretArns(project, service),
+ },
+ },
+ },
+ PolicyName: fmt.Sprintf("%sGrantAccessToSecrets", service.Name),
+ },
+ },
+ Tags: serviceTags(project, service),
+ }
+ template.Resources[serviceTaskRoleName(service)] = &iam.Role{
+ AssumeRolePolicyDocument: map[string]interface{}{
+ "Version": "2012-10-17",
+ "Statement": []map[string]interface{}{
+ {
+ "Action": []string{"sts:AssumeRole"},
+ "Effect": "Allow",
+ "Principal": map[string]interface{}{
+ "Service": "ecs-tasks.amazonaws.com",
+ },
+ },
+ },
+ },
+ Policies: []iam.Role_Policy{
+ {
+ PolicyDocument: service.Extensions[extensionRole],
+ PolicyName: fmt.Sprintf("%sPolicy", normalizeResourceName(service.Name)),
+ },
+ },
+ Tags: serviceTags(project, service),
}
- assignPublicIP := ecsapi.AssignPublicIpEnabled
- launchType := ecsapi.LaunchTypeFargate
- platformVersion := "1.4.0" // LATEST which is set to 1.3.0 (?) which doesn’t allow efs volumes.
- if requireEC2(service) {
- assignPublicIP = ecsapi.AssignPublicIpDisabled
- launchType = ecsapi.LaunchTypeEc2
- platformVersion = "" // The platform version must be null when specifying an EC2 launch type
+ for _, port := range service.Ports {
+ for network := range service.Networks {
+ template.Resources[fmt.Sprintf("%s%dIngress", normalizeResourceName(network), port.Target)] = &ec2.SecurityGroupIngress{
+ CidrIp: "0.0.0.0/0",
+ Description: fmt.Sprintf("%s:%d/%s on %s network", service.Name, port.Target, port.Protocol, network),
+ FromPort: int(port.Target),
+ GroupId: resources.securityGroups[network],
+ IpProtocol: "-1",
+ ToPort: int(port.Target),
+ }
+ }
+
+ template.Resources[serviceListenerName(service, port)] = &elasticloadbalancingv2.Listener{
+ DefaultActions: []elasticloadbalancingv2.Listener_Action{
+ {
+ ForwardConfig: &elasticloadbalancingv2.Listener_ForwardConfig{
+ TargetGroups: []elasticloadbalancingv2.Listener_TargetGroupTuple{
+ {
+ TargetGroupArn: cloudformation.Ref(serviceTargetGroupName(service, port)),
+ },
+ },
+ },
+ Type: "forward",
+ },
+ },
+ LoadBalancerArn: resources.loadBalancer,
+ Protocol: strings.ToUpper(port.Protocol),
+ Port: int(port.Target),
+ }
+ template.Resources[serviceTargetGroupName(service, port)] = &elasticloadbalancingv2.TargetGroup{
+ Port: int(port.Target),
+ Protocol: strings.ToUpper(port.Protocol),
+ Tags: serviceTags(project, service),
+ TargetType: "ip",
+ VpcId: resources.vpc,
+ }
}
- template.Resources[serviceResourceName(service.Name)] = &ecs.Service{
- AWSCloudFormationDependsOn: dependsOn,
- Cluster: resources.cluster.ARN(),
- DesiredCount: desiredCount,
+ template.Resources[serviceName(service)] = &ecs.Service{
+ AWSCloudFormationDependsOn: serviceDependsOn(service),
+ Cluster: cloudformation.GetAtt("Cluster", "Arn"),
+ DesiredCount: replicas(service),
DeploymentController: &ecs.Service_DeploymentController{
- Type: ecsapi.DeploymentControllerTypeEcs,
+ Type: "ECS",
},
DeploymentConfiguration: &ecs.Service_DeploymentConfiguration{
- MaximumPercent: maxPercent,
- MinimumHealthyPercent: minPercent,
+ MaximumPercent: 200,
+ MinimumHealthyPercent: 100,
},
- LaunchType: launchType,
- // TODO we miss support for https://github.com/aws/containers-roadmap/issues/631 to select a capacity provider
- LoadBalancers: serviceLB,
+ LaunchType: "FARGATE",
+ LoadBalancers: createServiceLoadBalancers(service),
NetworkConfiguration: &ecs.Service_NetworkConfiguration{
AwsvpcConfiguration: &ecs.Service_AwsVpcConfiguration{
- AssignPublicIp: assignPublicIP,
- SecurityGroups: resources.serviceSecurityGroups(service),
- Subnets: resources.subnetsIDs(),
+ AssignPublicIp: "ENABLED",
+ SecurityGroups: getServiceSecurityGroups(service, resources),
+ Subnets: resources.subnets,
},
},
- PlatformVersion: platformVersion,
- PropagateTags: ecsapi.PropagateTagsService,
- SchedulingStrategy: ecsapi.SchedulingStrategyReplica,
- ServiceRegistries: []ecs.Service_ServiceRegistry{serviceRegistry},
- Tags: serviceTags(project, service),
- TaskDefinition: cloudformation.Ref(normalizeResourceName(taskDefinition)),
+ PlatformVersion: "LATEST",
+ PropagateTags: "SERVICE",
+ SchedulingStrategy: "REPLICA",
+ ServiceRegistries: []ecs.Service_ServiceRegistry{
+ {
+ RegistryArn: cloudformation.GetAtt(serviceDiscoveryEntryName(service), "Arn"),
+ },
+ },
+ Tags: serviceTags(project, service),
+ TaskDefinition: cloudformation.Ref(serviceTaskDefinitionName(service)),
+ }
+
+ if err := createAutoscalingPolicy(project, template, service); err != nil {
+ return err
}
+
return nil
}
-const allProtocols = "-1"
+func createServiceLoadBalancers(service types.ServiceConfig) []ecs.Service_LoadBalancer {
+ serviceLoadBalancers := make([]ecs.Service_LoadBalancer, len(service.Ports))
-func (b *ComposeECS) createIngress(service types.ServiceConfig, net string, port types.ServicePortConfig, template *cloudformation.Template, resources awsResources) {
- protocol := strings.ToUpper(port.Protocol)
- if protocol == "" {
- protocol = allProtocols
- }
- ingress := fmt.Sprintf("%s%dIngress", normalizeResourceName(net), port.Target)
- template.Resources[ingress] = &ec2.SecurityGroupIngress{
- CidrIp: "0.0.0.0/0",
- Description: fmt.Sprintf("%s:%d/%s on %s network", service.Name, port.Target, port.Protocol, net),
- GroupId: resources.securityGroups[net],
- FromPort: int(port.Target),
- IpProtocol: protocol,
- ToPort: int(port.Target),
+ for i, port := range service.Ports {
+ serviceLoadBalancers[i] = ecs.Service_LoadBalancer{
+ ContainerName: service.Name,
+ ContainerPort: int(port.Target),
+ TargetGroupArn: cloudformation.Ref(serviceTargetGroupName(service, port)),
+ }
}
+
+ return serviceLoadBalancers
}
-func (b *ComposeECS) createSecret(project *types.Project, name string, s types.SecretConfig, template *cloudformation.Template) error {
- if s.External.External {
+func createRepositoryCredentials(service types.ServiceConfig) *ecs.TaskDefinition_RepositoryCredentials {
+ if value, ok := service.Extensions[extensionPullCredentials]; ok {
+ return &ecs.TaskDefinition_RepositoryCredentials{
+ CredentialsParameter: value.(string),
+ }
+ } else {
return nil
}
- sensitiveData, err := os.ReadFile(s.File)
- if err != nil {
- return err
+}
+
+func createTaskSecrets(project *types.Project, service types.ServiceConfig) []ecs.TaskDefinition_Secret {
+ taskSecrets := make([]ecs.TaskDefinition_Secret, len(service.Secrets))
+
+ for i, s := range service.Secrets {
+ if s.Target == "" {
+ s.Target = s.Source
+ }
+ taskSecrets[i] = ecs.TaskDefinition_Secret{
+ Name: s.Target,
+ ValueFrom: project.Secrets[s.Source].Name,
+ }
}
- resource := fmt.Sprintf("%sSecret", normalizeResourceName(s.Name))
- template.Resources[resource] = &secretsmanager.Secret{
- Description: fmt.Sprintf("Secret %s", s.Name),
- SecretString: string(sensitiveData),
- Tags: projectTags(project),
+ return taskSecrets
+}
+
+func replicas(service types.ServiceConfig) int {
+ if service.Deploy != nil && service.Deploy.Replicas != nil {
+ return *service.Deploy.Replicas
}
- s.Name = cloudformation.Ref(resource)
- project.Secrets[name] = s
- return nil
+
+ return 1
+}
+
+func serviceName(service types.ServiceConfig) string {
+ return fmt.Sprintf("%sService", normalizeResourceName(service.Name))
+}
+
+func serviceAutoScalingRoleName(service types.ServiceConfig) string {
+ return fmt.Sprintf("%sAutoScalingRole", normalizeResourceName(service.Name))
}
-func (b *ComposeECS) createLogGroup(project *types.Project, template *cloudformation.Template) {
- retention := 0
- if v, ok := project.Extensions[extensionRetention]; ok {
- retention = v.(int)
+func serviceDependsOn(service types.ServiceConfig) []string {
+ var dependsOn []string
+
+ for dependency := range service.DependsOn {
+ dependsOn = append(dependsOn, fmt.Sprintf("%sService", normalizeResourceName(dependency)))
}
- logGroup := fmt.Sprintf("/docker-compose/%s", project.Name)
- template.Resources["LogGroup"] = &logs.LogGroup{
- LogGroupName: logGroup,
- RetentionInDays: retention,
+
+ for _, port := range service.Ports {
+ dependsOn = append(dependsOn, serviceListenerName(service, port))
}
+
+ return dependsOn
}
-func computeRollingUpdateLimits(service types.ServiceConfig) (int, int, error) {
- maxPercent := 200
- minPercent := 100
- if service.Deploy == nil || service.Deploy.UpdateConfig == nil {
- return minPercent, maxPercent, nil
+func serviceDiscoveryEntryName(service types.ServiceConfig) string {
+ return fmt.Sprintf("%sServiceDiscoveryEntry", normalizeResourceName(service.Name))
+}
+
+func serviceListenerName(service types.ServiceConfig, port types.ServicePortConfig) string {
+ return fmt.Sprintf("%s%s%dListener", normalizeResourceName(service.Name), strings.ToUpper(port.Protocol), port.Target)
+}
+
+func serviceScalableTargetName(service types.ServiceConfig) string {
+ return fmt.Sprintf("%sScalableTarget", normalizeResourceName(service.Name))
+}
+
+func serviceScalingPolicyName(service types.ServiceConfig) string {
+ return fmt.Sprintf("%sScalingPolicy", normalizeResourceName(service.Name))
+}
+
+func serviceTaskDefinitionName(service types.ServiceConfig) string {
+ return fmt.Sprintf("%sTaskDefinition", normalizeResourceName(service.Name))
+}
+
+func serviceTaskExecutionRoleName(service types.ServiceConfig) string {
+ return fmt.Sprintf("%sTaskExecutionRole", normalizeResourceName(service.Name))
+}
+
+func serviceTargetGroupName(service types.ServiceConfig, port types.ServicePortConfig) string {
+ return fmt.Sprintf("%s%s%sTargetGroup", normalizeResourceName(service.Name), strings.ToUpper(port.Protocol), port.Published)
+}
+
+func serviceTaskRoleName(service types.ServiceConfig) string {
+ return fmt.Sprintf("%sTaskRole", normalizeResourceName(service.Name))
+}
+
+var (
+ regex = regexp.MustCompile("[^a-zA-Z0-9]+")
+ title = cases.Title(language.English)
+)
+
+func normalizeResourceName(s string) string {
+ return title.String(regex.ReplaceAllString(s, ""))
+}
+
+func createEnvironment(service types.ServiceConfig) []ecs.TaskDefinition_KeyValuePair {
+ var pairs []ecs.TaskDefinition_KeyValuePair
+
+ for k, v := range service.Environment {
+ pairs = append(pairs, ecs.TaskDefinition_KeyValuePair{
+ Name: k,
+ Value: *v,
+ })
}
- updateConfig := service.Deploy.UpdateConfig
- min, okMin := updateConfig.Extensions[extensionMinPercent]
- if okMin {
- minPercent = min.(int)
+
+ sort.Slice(pairs, func(i, j int) bool {
+ return pairs[i].Name < pairs[j].Name
+ })
+
+ return pairs
+}
+
+const miB = 1024 * 1024
+
+func toLimits(service types.ServiceConfig) (string, string, error) {
+ mem, cpu, err := getConfiguredLimits(service)
+ if err != nil {
+ return "", "", err
+ }
+
+ // All possible cpu/mem values for Fargate
+ fargateCPUToMem := map[int64][]types.UnitBytes{
+ 256: {512, 1024, 2048},
+ 512: {1024, 2048, 3072, 4096},
+ 1024: {2048, 3072, 4096, 5120, 6144, 7168, 8192},
+ 2048: {4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360, 16384},
+ 4096: {8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360, 16384, 17408, 18432, 19456, 20480, 21504, 22528, 23552, 24576, 25600, 26624, 27648, 28672, 29696, 30720},
+ }
+ cpuLimit := "256"
+ memLimit := "512"
+ if mem == 0 && cpu == 0 {
+ return cpuLimit, memLimit, nil
+ }
+
+ var cpus []int64
+ for k := range fargateCPUToMem {
+ cpus = append(cpus, k)
+ }
+ sort.Slice(cpus, func(i, j int) bool { return cpus[i] < cpus[j] })
+
+ for _, fargateCPU := range cpus {
+ options := fargateCPUToMem[fargateCPU]
+ if cpu <= fargateCPU {
+ for _, m := range options {
+ if mem <= m*miB {
+ cpuLimit = strconv.FormatInt(fargateCPU, 10)
+ memLimit = strconv.FormatInt(int64(m), 10)
+ return cpuLimit, memLimit, nil
+ }
+ }
+ }
}
- max, okMax := updateConfig.Extensions[extensionMaxPercent]
- if okMax {
- maxPercent = max.(int)
+ return "", "", fmt.Errorf("the resources requested are not supported by ECS/Fargate")
+}
+
+func getConfiguredLimits(service types.ServiceConfig) (types.UnitBytes, int64, error) {
+ if service.Deploy == nil {
+ return 0, 0, nil
+ }
+
+ limits := service.Deploy.Resources.Limits
+ if limits == nil {
+ limits = service.Deploy.Resources.Reservations
}
- if okMin && okMax {
- return minPercent, maxPercent, nil
+ if limits == nil {
+ return 0, 0, nil
}
- if updateConfig.Parallelism != nil {
- parallelism := int(*updateConfig.Parallelism)
- if service.Deploy.Replicas == nil {
- return minPercent, maxPercent,
- fmt.Errorf("rolling update configuration require deploy.replicas to be set")
- }
- replicas := int(*service.Deploy.Replicas)
- if replicas < parallelism {
- return minPercent, maxPercent,
- fmt.Errorf("deploy.replicas (%d) must be greater than deploy.update_config.parallelism (%d)", replicas, parallelism)
- }
- if !okMin {
- minPercent = (replicas - parallelism) * 100 / replicas
- }
- if !okMax {
- maxPercent = (replicas + parallelism) * 100 / replicas
- }
+ if limits.NanoCPUs == "" {
+ return limits.MemoryBytes, 0, nil
}
- return minPercent, maxPercent, nil
-}
-
-func (b *ComposeECS) createListener(service types.ServiceConfig, port types.ServicePortConfig,
- template *cloudformation.Template,
- targetGroupName string, loadBalancer awsResource, protocol string) string {
- listenerName := fmt.Sprintf(
- "%s%s%dListener",
- normalizeResourceName(service.Name),
- strings.ToUpper(port.Protocol),
- port.Target,
- )
- // add listener to dependsOn
- // https://stackoverflow.com/questions/53971873/the-target-group-does-not-have-an-associated-load-balancer
- template.Resources[listenerName] = &elasticloadbalancingv2.Listener{
- DefaultActions: []elasticloadbalancingv2.Listener_Action{
- {
- ForwardConfig: &elasticloadbalancingv2.Listener_ForwardConfig{
- TargetGroups: []elasticloadbalancingv2.Listener_TargetGroupTuple{
- {
- TargetGroupArn: cloudformation.Ref(targetGroupName),
- },
- },
- },
- Type: elbv2.ActionTypeEnumForward,
- },
- },
- LoadBalancerArn: loadBalancer.ARN(),
- Protocol: protocol,
- Port: int(port.Target),
+ v, err := opts.ParseCPUs(limits.NanoCPUs)
+ if err != nil {
+ return 0, 0, err
}
- return listenerName
+
+ return limits.MemoryBytes, v / 1e6, nil
}
-func (b *ComposeECS) createTargetGroup(project *types.Project, service types.ServiceConfig, port types.ServicePortConfig, template *cloudformation.Template, protocol string, vpc string) string {
- targetGroupName := fmt.Sprintf(
- "%s%s%dTargetGroup",
- normalizeResourceName(service.Name),
- strings.ToUpper(port.Protocol),
- port.Published,
- )
- template.Resources[targetGroupName] = &elasticloadbalancingv2.TargetGroup{
- Port: int(port.Target),
- Protocol: protocol,
- Tags: projectTags(project),
- TargetType: elbv2.TargetTypeEnumIp,
- VpcId: vpc,
+func getServiceSecurityGroups(service types.ServiceConfig, resources resources) []string {
+ var groups []string
+
+ for network := range service.Networks {
+ groups = append(groups, resources.securityGroups[network])
}
- return targetGroupName
+
+ return groups
}
-func (b *ComposeECS) createServiceRegistry(service types.ServiceConfig, template *cloudformation.Template, healthCheck *cloudmap.Service_HealthCheckConfig) ecs.Service_ServiceRegistry {
- serviceRegistration := fmt.Sprintf("%sServiceDiscoveryEntry", normalizeResourceName(service.Name))
- serviceRegistry := ecs.Service_ServiceRegistry{
- RegistryArn: cloudformation.GetAtt(serviceRegistration, "Arn"),
- }
+func getSecretArns(project *types.Project, service types.ServiceConfig) []string {
+ var secretArns []string
- template.Resources[serviceRegistration] = &cloudmap.Service{
- Description: fmt.Sprintf("%q service discovery entry in Cloud Map", service.Name),
- HealthCheckConfig: healthCheck,
- HealthCheckCustomConfig: &cloudmap.Service_HealthCheckCustomConfig{
- FailureThreshold: 1,
- },
- Name: service.Name,
- NamespaceId: cloudformation.Ref("CloudMap"),
- DnsConfig: &cloudmap.Service_DnsConfig{
- DnsRecords: []cloudmap.Service_DnsRecord{
- {
- TTL: 60,
- Type: cloudmapapi.RecordTypeA,
- },
- },
- RoutingPolicy: cloudmapapi.RoutingPolicyMultivalue,
- },
+ if value, ok := service.Extensions[extensionPullCredentials]; ok {
+ secretArns = append(secretArns, value.(string))
}
- return serviceRegistry
-}
-func (b *ComposeECS) createTaskExecutionRole(project *types.Project, service types.ServiceConfig, template *cloudformation.Template) string {
- taskExecutionRole := fmt.Sprintf("%sTaskExecutionRole", normalizeResourceName(service.Name))
- policies := b.createPolicies(project, service)
- template.Resources[taskExecutionRole] = &iam.Role{
- AssumeRolePolicyDocument: ecsTaskAssumeRolePolicyDocument,
- Policies: policies,
- ManagedPolicyArns: []string{
- ecsTaskExecutionPolicy,
- ecrReadOnlyPolicy,
- },
- Tags: serviceTags(project, service),
+ for _, secret := range service.Secrets {
+ secretArns = append(secretArns, project.Secrets[secret.Source].Name)
}
- return taskExecutionRole
+
+ return secretArns
}
-func (b *ComposeECS) createTaskRole(project *types.Project, service types.ServiceConfig, template *cloudformation.Template, resources awsResources) (string, error) {
- taskRole := fmt.Sprintf("%sTaskRole", normalizeResourceName(service.Name))
- rolePolicies := []iam.Role_Policy{}
- if roles, ok := service.Extensions[extensionRole]; ok {
- rolePolicies = append(rolePolicies, iam.Role_Policy{
- PolicyName: fmt.Sprintf("%sPolicy", normalizeResourceName(service.Name)),
- PolicyDocument: roles,
- })
- }
- for _, vol := range service.Volumes {
- if vol.Source == "" {
- return "", fmt.Errorf(
- "service %s has an invalid volume %s: ECS does not support sourceless volumes",
- service.Name,
- vol.Target,
- )
- }
- rolePolicies = append(rolePolicies, iam.Role_Policy{
- PolicyName: fmt.Sprintf("%s%sVolumeMountPolicy", normalizeResourceName(service.Name), normalizeResourceName(vol.Source)),
- PolicyDocument: volumeMountPolicyDocument(vol.Source, resources.filesystems[vol.Source].ARN()),
- })
+func toPortMappings(ports []types.ServicePortConfig) []ecs.TaskDefinition_PortMapping {
+ if len(ports) == 0 {
+ return nil
}
- managedPolicies := []string{}
- if v, ok := service.Extensions[extensionManagedPolicies]; ok {
- for _, s := range v.([]interface{}) {
- managedPolicies = append(managedPolicies, s.(string))
+
+ m := make([]ecs.TaskDefinition_PortMapping, len(ports))
+ for i, p := range ports {
+ m[i] = ecs.TaskDefinition_PortMapping{
+ ContainerPort: int(p.Target),
+ Protocol: p.Protocol,
}
}
- if len(rolePolicies) == 0 && len(managedPolicies) == 0 {
- return "", nil
- }
- template.Resources[taskRole] = &iam.Role{
- AssumeRolePolicyDocument: ecsTaskAssumeRolePolicyDocument,
- Policies: rolePolicies,
- ManagedPolicyArns: managedPolicies,
- Tags: serviceTags(project, service),
- }
- return taskRole, nil
+ return m
}
-func (b *ComposeECS) createCloudMap(project *types.Project, template *cloudformation.Template, vpc string) {
- template.Resources["CloudMap"] = &cloudmap.PrivateDnsNamespace{
- Description: fmt.Sprintf("Service Map for Docker Compose project %s", project.Name),
- Name: fmt.Sprintf("%s.local", project.Name),
- Vpc: vpc,
+func toUlimits(ulimits map[string]*types.UlimitsConfig) []ecs.TaskDefinition_Ulimit {
+ if len(ulimits) == 0 {
+ return nil
+ }
+
+ u := make([]ecs.TaskDefinition_Ulimit, len(ulimits))
+ for k, v := range ulimits {
+ u = append(u, ecs.TaskDefinition_Ulimit{
+ Name: k,
+ SoftLimit: v.Soft,
+ HardLimit: v.Hard,
+ })
}
+ return u
}
-func (b *ComposeECS) createPolicies(project *types.Project, service types.ServiceConfig) []iam.Role_Policy {
- var arns []string
- if value, ok := service.Extensions[extensionPullCredentials]; ok {
- arns = append(arns, value.(string))
+func toHealthCheck(check *types.HealthCheckConfig) *ecs.TaskDefinition_HealthCheck {
+ if check == nil {
+ return nil
}
- for _, secret := range service.Secrets {
- arns = append(arns, project.Secrets[secret.Source].Name)
+ retries := 0
+ if check.Retries != nil {
+ retries = int(*check.Retries)
}
- if len(arns) > 0 {
- return []iam.Role_Policy{
- {
- PolicyDocument: &PolicyDocument{
- Statement: []PolicyStatement{
- {
- Effect: "Allow",
- Action: []string{actionGetSecretValue, actionGetParameters, actionDecrypt},
- Resource: arns,
- },
- },
- },
- PolicyName: fmt.Sprintf("%sGrantAccessToSecrets", service.Name),
- },
- }
+ return &ecs.TaskDefinition_HealthCheck{
+ Command: check.Test,
+ Interval: durationToInt(check.Interval),
+ Retries: retries,
+ StartPeriod: durationToInt(check.StartPeriod),
+ Timeout: durationToInt(check.Timeout),
}
- return nil
}
-func networkResourceName(network string) string {
- return fmt.Sprintf("%sNetwork", normalizeResourceName(network))
+func durationToInt(interval *types.Duration) int {
+ if interval == nil {
+ return 0
+ }
+ v := int(time.Duration(*interval).Seconds())
+ return v
}
-func serviceResourceName(service string) string {
- return fmt.Sprintf("%sService", normalizeResourceName(service))
+func projectTags(project *types.Project) []tags.Tag {
+ return []tags.Tag{
+ {
+ Key: api.ProjectLabel,
+ Value: project.Name,
+ },
+ }
}
-func volumeResourceName(service string) string {
- return fmt.Sprintf("%sFilesystem", normalizeResourceName(service))
+func serviceTags(project *types.Project, service types.ServiceConfig) []tags.Tag {
+ return append(projectTags(project),
+ tags.Tag{
+ Key: api.ServiceLabel,
+ Value: service.Name,
+ })
}
-func normalizeResourceName(s string) string {
- //nolint:staticcheck // Preserving for compatibility
- return strings.Title(regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(s, ""))
+//goland:noinspection GoUnusedGlobalVariable
+var compatibleComposeAttributes = []string{
+ "services.command",
+ "services.container_name",
+ "services.depends_on",
+ "services.deploy",
+ "services.deploy.replicas",
+ "services.deploy.resources.limits",
+ "services.deploy.resources.limits.cpus",
+ "services.deploy.resources.limits.memory",
+ "services.deploy.update_config",
+ "services.deploy.update_config.parallelism",
+ "services.entrypoint",
+ "services.environment",
+ "services.healthcheck",
+ "services.healthcheck.interval",
+ "services.healthcheck.retries",
+ "services.healthcheck.start_period",
+ "services.healthcheck.test",
+ "services.healthcheck.timeout",
+ "services.image",
+ "services.labels",
+ "services.ports",
+ "services.ports.mode",
+ "services.ports.target",
+ "services.ports.protocol",
+ "services.scale",
+ "services.secrets",
+ "services.secrets.source",
+ "services.secrets.target",
+ "services.user",
+ "secrets.external",
+ "secrets.name",
+ "networks.external",
+ "networks.name",
}
diff --git a/ecs/cloudformation_test.go b/ecs/cloudformation_test.go
index c94d3802..d5cd6eb4 100644
--- a/ecs/cloudformation_test.go
+++ b/ecs/cloudformation_test.go
@@ -1,119 +1,38 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
import (
- "context"
- "errors"
- "fmt"
- "os"
"reflect"
"testing"
- "github.com/aws/aws-sdk-go/service/elbv2"
"github.com/awslabs/goformation/v4/cloudformation"
+ "github.com/awslabs/goformation/v4/cloudformation/applicationautoscaling"
"github.com/awslabs/goformation/v4/cloudformation/ec2"
"github.com/awslabs/goformation/v4/cloudformation/ecs"
- "github.com/awslabs/goformation/v4/cloudformation/efs"
"github.com/awslabs/goformation/v4/cloudformation/elasticloadbalancingv2"
"github.com/awslabs/goformation/v4/cloudformation/iam"
- "github.com/awslabs/goformation/v4/cloudformation/logs"
- "github.com/compose-spec/compose-go/loader"
- "github.com/compose-spec/compose-go/types"
+ "github.com/compose-spec/compose-go/v2/loader"
+ "github.com/compose-spec/compose-go/v2/types"
"github.com/docker/compose/v2/pkg/api"
- "github.com/golang/mock/gomock"
"gotest.tools/v3/assert"
- "gotest.tools/v3/golden"
)
-func TestSimpleConvert(t *testing.T) {
- bytes, err := os.ReadFile("testdata/input/simple-single-service.yaml")
- assert.NilError(t, err)
- template := convertYaml(t, string(bytes), nil, useDefaultVPC)
- resultAsJSON, err := marshall(template, "yaml")
- assert.NilError(t, err)
- result := fmt.Sprintf("%s\n", string(resultAsJSON))
- expected := "simple-cloudformation-conversion.golden"
- golden.Assert(t, result, expected)
-}
-
-func TestLogging(t *testing.T) {
- template := convertYaml(t, `
-services:
- foo:
- image: hello_world
- logging:
- options:
- awslogs-datetime-pattern: "FOO"
-
-x-aws-logs_retention: 10
-`, nil, useDefaultVPC)
- def := template.Resources["FooTaskDefinition"].(*ecs.TaskDefinition)
- logging := getMainContainer(def, t).LogConfiguration
- if logging != nil {
- assert.Equal(t, logging.Options["awslogs-datetime-pattern"], "FOO")
- } else {
- t.Fatal("Logging not configured")
- }
-
- logGroup := template.Resources["LogGroup"].(*logs.LogGroup)
- assert.Equal(t, logGroup.RetentionInDays, 10)
-}
-
-func TestEnvFile(t *testing.T) {
- template := convertYaml(t, `
-services:
- foo:
- image: hello_world
- env_file:
- - testdata/input/envfile
-`, nil, useDefaultVPC)
- def := template.Resources["FooTaskDefinition"].(*ecs.TaskDefinition)
- env := getMainContainer(def, t).Environment
- var found bool
- for _, pair := range env {
- if pair.Name == "FOO" {
- assert.Equal(t, pair.Value, "BAR")
- found = true
- }
- }
- assert.Check(t, found, "environment variable FOO not set")
-}
-
-func TestEnvFileAndEnv(t *testing.T) {
+func TestAutoScaling(t *testing.T) {
template := convertYaml(t, `
services:
foo:
image: hello_world
- env_file:
- - testdata/input/envfile
- environment:
- - "FOO=ZOT"
-`, nil, useDefaultVPC)
- def := template.Resources["FooTaskDefinition"].(*ecs.TaskDefinition)
- env := getMainContainer(def, t).Environment
- var found bool
- for _, pair := range env {
- if pair.Name == "FOO" {
- assert.Equal(t, pair.Value, "ZOT")
- found = true
- }
- }
- assert.Check(t, found, "environment variable FOO not set")
+ deploy:
+ x-aws-autoscaling:
+ cpu: 75
+ max: 10
+`, nil)
+ target := template.Resources["FooScalableTarget"].(*applicationautoscaling.ScalableTarget)
+ assert.Check(t, target != nil) //nolint:staticcheck
+ assert.Check(t, target.MaxCapacity == 10) //nolint:staticcheck
+
+ policy := template.Resources["FooScalingPolicy"].(*applicationautoscaling.ScalingPolicy)
+ assert.Check(t, policy != nil) //nolint:staticcheck
+ assert.Check(t, policy.TargetTrackingScalingPolicyConfiguration.TargetValue == float64(75)) //nolint:staticcheck
}
func TestRollingUpdateLimits(t *testing.T) {
@@ -125,45 +44,30 @@ services:
replicas: 4
update_config:
parallelism: 2
-`, nil, useDefaultVPC)
+`, nil)
service := template.Resources["FooService"].(*ecs.Service)
assert.Check(t, service.DeploymentConfiguration.MaximumPercent == 150)
assert.Check(t, service.DeploymentConfiguration.MinimumHealthyPercent == 50)
}
-func TestRollingUpdateExtension(t *testing.T) {
- template := convertYaml(t, `
-services:
- foo:
- image: hello_world
- deploy:
- update_config:
- x-aws-min_percent: 25
- x-aws-max_percent: 125
-`, nil, useDefaultVPC)
- service := template.Resources["FooService"].(*ecs.Service)
- assert.Check(t, service.DeploymentConfiguration.MaximumPercent == 125)
- assert.Check(t, service.DeploymentConfiguration.MinimumHealthyPercent == 25)
-}
-
func TestRolePolicy(t *testing.T) {
template := convertYaml(t, `
services:
foo:
image: hello_world
x-aws-pull_credentials: "secret"
-`, nil, useDefaultVPC)
+`, nil)
x := template.Resources["FooTaskExecutionRole"]
assert.Check(t, x != nil)
role := *(x.(*iam.Role))
- assert.Check(t, role.ManagedPolicyArns[0] == ecsTaskExecutionPolicy)
- assert.Check(t, role.ManagedPolicyArns[1] == ecrReadOnlyPolicy)
+ assert.Check(t, role.ManagedPolicyArns[0] == "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly")
+ assert.Check(t, role.ManagedPolicyArns[1] == "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy")
// We expect an extra policy has been created for x-aws-pull_credentials
assert.Check(t, len(role.Policies) == 1)
- policy := role.Policies[0].PolicyDocument.(*PolicyDocument)
+ policy := role.Policies[0].PolicyDocument
expected := []string{"secretsmanager:GetSecretValue", "ssm:GetParameters", "kms:Decrypt"}
- assert.DeepEqual(t, expected, policy.Statement[0].Action)
- assert.DeepEqual(t, []string{"secret"}, policy.Statement[0].Resource)
+ assert.DeepEqual(t, expected, policy.(map[string]interface{})["Statement"].([]map[string]interface{})[0]["Action"])
+ assert.DeepEqual(t, []string{"secret"}, policy.(map[string]interface{})["Statement"].([]map[string]interface{})[0]["Resource"])
}
func TestMapNetworksToSecurityGroups(t *testing.T) {
@@ -180,7 +84,7 @@ networks:
name: public
back-tier:
internal: true
-`, nil, useDefaultVPC)
+`, nil)
assert.Check(t, template.Resources["FronttierNetwork"] != nil)
assert.Check(t, template.Resources["BacktierNetwork"] != nil)
assert.Check(t, template.Resources["BacktierNetworkIngress"] != nil)
@@ -208,12 +112,12 @@ func TestLoadBalancerTypeApplication(t *testing.T) {
`,
}
for _, y := range cases {
- template := convertYaml(t, y, nil, useDefaultVPC)
+ template := convertYaml(t, y, nil)
lb := template.Resources["LoadBalancer"]
assert.Check(t, lb != nil)
loadBalancer := *lb.(*elasticloadbalancingv2.LoadBalancer)
assert.Check(t, len(loadBalancer.Name) <= 32)
- assert.Check(t, loadBalancer.Type == elbv2.LoadBalancerTypeEnumApplication)
+ assert.Check(t, loadBalancer.Type == "application")
assert.Check(t, len(loadBalancer.SecurityGroups) > 0)
}
}
@@ -225,7 +129,7 @@ services:
image: nginx
foo:
image: bar
-`, nil, useDefaultVPC)
+`, nil)
for _, r := range template.Resources {
assert.Check(t, r.AWSCloudFormationType() != "AWS::ElasticLoadBalancingV2::TargetGroup")
assert.Check(t, r.AWSCloudFormationType() != "AWS::ElasticLoadBalancingV2::Listener")
@@ -240,7 +144,7 @@ services:
image: nginx
deploy:
replicas: 10
-`, nil, useDefaultVPC)
+`, nil)
s := template.Resources["TestService"]
assert.Check(t, s != nil)
service := *s.(*ecs.Service)
@@ -252,7 +156,7 @@ func TestTaskSizeConvert(t *testing.T) {
services:
test:
image: nginx
-`, nil, useDefaultVPC)
+`, nil)
def := template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
assert.Equal(t, def.Cpu, "256")
assert.Equal(t, def.Memory, "512")
@@ -266,7 +170,7 @@ services:
limits:
cpus: '0.5'
memory: 2048M
-`, nil, useDefaultVPC)
+`, nil)
def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
assert.Equal(t, def.Cpu, "512")
assert.Equal(t, def.Memory, "2048")
@@ -280,7 +184,7 @@ services:
limits:
cpus: '4'
memory: 8192M
-`, nil, useDefaultVPC)
+`, nil)
def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
assert.Equal(t, def.Cpu, "4096")
assert.Equal(t, def.Memory, "8192")
@@ -294,12 +198,7 @@ services:
limits:
cpus: '4'
memory: 792Mb
- reservations:
- generic_resources:
- - discrete_resource_spec:
- kind: gpus
- value: 2
-`, nil, useDefaultVPC, useGPU)
+`, nil)
def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
assert.Equal(t, def.Cpu, "4000")
assert.Equal(t, def.Memory, "792")
@@ -310,12 +209,7 @@ services:
image: nginx
deploy:
resources:
- reservations:
- generic_resources:
- - discrete_resource_spec:
- kind: gpus
- value: 2
-`, nil, useDefaultVPC, useGPU)
+`, nil)
def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
assert.Equal(t, def.Cpu, "")
assert.Equal(t, def.Memory, "")
@@ -330,7 +224,7 @@ services:
devices:
- capabilities: [gpu]
count: 2
-`, nil, useDefaultVPC, useGPU)
+`, nil)
def = template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
assert.Equal(t, def.Cpu, "")
assert.Equal(t, def.Memory, "")
@@ -344,11 +238,11 @@ services:
ports:
- 80:80
- 88:88
-`, nil, useDefaultVPC)
+`, nil)
lb := template.Resources["LoadBalancer"]
assert.Check(t, lb != nil)
loadBalancer := *lb.(*elasticloadbalancingv2.LoadBalancer)
- assert.Check(t, loadBalancer.Type == elbv2.LoadBalancerTypeEnumNetwork)
+ assert.Check(t, loadBalancer.Type == "network")
}
func TestUseExternalNetwork(t *testing.T) {
@@ -360,9 +254,7 @@ networks:
default:
external: true
name: sg-123abc
-`, nil, useDefaultVPC, func(m *MockAPIMockRecorder) {
- m.SecurityGroupExists(gomock.Any(), "sg-123abc").Return(true, nil)
- })
+`, nil)
assert.Check(t, template.Resources["DefaultNetwork"] == nil)
assert.Check(t, template.Resources["DefaultNetworkIngress"] == nil)
s := template.Resources["TestService"].(*ecs.Service)
@@ -370,120 +262,6 @@ networks:
assert.Check(t, s.NetworkConfiguration.AwsvpcConfiguration.SecurityGroups[0] == "sg-123abc") //nolint:staticcheck
}
-func TestUseExternalVolume(t *testing.T) {
- template := convertYaml(t, `
-services:
- test:
- image: nginx
-volumes:
- db-data:
- external: true
- name: fs-123abc
-`, nil, useDefaultVPC, func(m *MockAPIMockRecorder) {
- m.ResolveFileSystem(gomock.Any(), "fs-123abc").Return(existingAWSResource{id: "fs-123abc"}, nil)
- })
- s := template.Resources["DbdataNFSMountTargetOnSubnet1"].(*efs.MountTarget)
- assert.Check(t, s != nil) //nolint:staticcheck
- assert.Equal(t, s.FileSystemId, "fs-123abc") //nolint:staticcheck
-
- s = template.Resources["DbdataNFSMountTargetOnSubnet2"].(*efs.MountTarget)
- assert.Check(t, s != nil) //nolint:staticcheck
- assert.Equal(t, s.FileSystemId, "fs-123abc") //nolint:staticcheck
-}
-
-func TestCreateVolume(t *testing.T) {
- template := convertYaml(t, `
-services:
- test:
- image: nginx
-volumes:
- db-data:
- driver_opts:
- backup_policy: ENABLED
- lifecycle_policy: AFTER_30_DAYS
- performance_mode: maxIO
- throughput_mode: provisioned
- provisioned_throughput: 1024
-`, nil, useDefaultVPC, func(m *MockAPIMockRecorder) {
- m.ListFileSystems(gomock.Any(), map[string]string{
- api.ProjectLabel: t.Name(),
- api.VolumeLabel: "db-data",
- }).Return(nil, nil)
- })
- n := volumeResourceName("db-data")
- f := template.Resources[n].(*efs.FileSystem)
- assert.Check(t, f != nil) //nolint:staticcheck
- assert.Equal(t, f.BackupPolicy.Status, "ENABLED") //nolint:staticcheck
- assert.Equal(t, f.LifecyclePolicies[0].TransitionToIA, "AFTER_30_DAYS") //nolint:staticcheck
- assert.Equal(t, f.PerformanceMode, "maxIO") //nolint:staticcheck
- assert.Equal(t, f.ThroughputMode, "provisioned") //nolint:staticcheck
- assert.Equal(t, f.ProvisionedThroughputInMibps, float64(1024)) //nolint:staticcheck
-
- s := template.Resources["DbdataNFSMountTargetOnSubnet1"].(*efs.MountTarget)
- assert.Check(t, s != nil) //nolint:staticcheck
- assert.Equal(t, s.FileSystemId, cloudformation.Ref(n)) //nolint:staticcheck
-}
-
-func TestCreateSourcelessVolume(t *testing.T) {
- convertYaml(t, `
-services:
- test:
- image: nginx
- volumes:
- - db-data
-volumes:
- db-data:
-`,
- errors.New("service test has an invalid volume db-data: ECS does not support sourceless volumes"),
- useDefaultVPC, func(m *MockAPIMockRecorder) {
- m.ListFileSystems(gomock.Any(), map[string]string{
- api.ProjectLabel: t.Name(),
- api.VolumeLabel: "db-data",
- }).Return(nil, nil)
- })
-}
-
-func TestCreateAccessPoint(t *testing.T) {
- template := convertYaml(t, `
-services:
- test:
- image: nginx
-volumes:
- db-data:
- driver_opts:
- uid: 1002
- gid: 1002
-`, nil, useDefaultVPC, func(m *MockAPIMockRecorder) {
- m.ListFileSystems(gomock.Any(), gomock.Any()).Return(nil, nil)
- })
- a := template.Resources["DbdataAccessPoint"].(*efs.AccessPoint)
- assert.Check(t, a != nil) //nolint:staticcheck
- assert.Equal(t, a.PosixUser.Uid, "1002") //nolint:staticcheck
- assert.Equal(t, a.PosixUser.Gid, "1002") //nolint:staticcheck
-}
-
-func TestReusePreviousVolume(t *testing.T) {
- template := convertYaml(t, `
-services:
- test:
- image: nginx
-volumes:
- db-data: {}
-`, nil, useDefaultVPC, func(m *MockAPIMockRecorder) {
- m.ListFileSystems(gomock.Any(), map[string]string{
- api.ProjectLabel: t.Name(),
- api.VolumeLabel: "db-data",
- }).Return([]awsResource{
- existingAWSResource{
- id: "fs-123abc",
- },
- }, nil)
- })
- s := template.Resources["DbdataNFSMountTargetOnSubnet1"].(*efs.MountTarget)
- assert.Check(t, s != nil) //nolint:staticcheck
- assert.Equal(t, s.FileSystemId, "fs-123abc") //nolint:staticcheck
-}
-
func TestServiceMapping(t *testing.T) {
template := convertYaml(t, `
services:
@@ -493,25 +271,15 @@ services:
entrypoint: "entrypoint"
environment:
- "FOO=BAR"
- cap_add:
- - SYS_PTRACE
- cap_drop:
- - SYSLOG
- init: true
user: "user"
- working_dir: "working_dir"
-`, nil, useDefaultVPC)
+`, nil)
def := template.Resources["TestTaskDefinition"].(*ecs.TaskDefinition)
container := getMainContainer(def, t)
assert.Equal(t, container.Image, "image")
assert.Equal(t, container.Command[0], "command")
assert.Equal(t, container.EntryPoint[0], "entrypoint")
assert.Equal(t, get(container.Environment, "FOO"), "BAR")
- assert.Check(t, container.LinuxParameters.InitProcessEnabled)
- assert.Equal(t, container.LinuxParameters.Capabilities.Add[0], "SYS_PTRACE")
- assert.Equal(t, container.LinuxParameters.Capabilities.Drop[0], "SYSLOG")
assert.Equal(t, container.User, "user")
- assert.Equal(t, container.WorkingDirectory, "working_dir")
}
func get(l []ecs.TaskDefinition_KeyValuePair, name string) string {
@@ -531,7 +299,7 @@ services:
ports:
- 80:80
- 88:88
-`, nil, useDefaultVPC)
+`, nil)
for _, r := range template.Resources {
tags := reflect.Indirect(reflect.ValueOf(r)).FieldByName("Tags")
if !tags.IsValid() {
@@ -553,46 +321,19 @@ x-aws-cluster: "arn:aws:ecs:region:account:cluster/name"
services:
test:
image: nginx
-`, nil, useDefaultVPC, func(m *MockAPIMockRecorder) {
- m.ResolveCluster(gomock.Any(), "arn:aws:ecs:region:account:cluster/name").Return(existingAWSResource{
- arn: "arn:aws:ecs:region:account:cluster/name",
- id: "name",
- }, nil)
- })
+`, nil)
assert.Equal(t, template.Metadata["Cluster"], "arn:aws:ecs:region:account:cluster/name")
}
-func TestARNUsedAsVpcID(t *testing.T) {
- convertYaml(t, `
-x-aws-vpc: "arn:aws:ec2:us-west-1:EXAMPLE:vpc/vpc-1234acbd"
-services:
- test:
- image: nginx
-`, nil, func(m *MockAPIMockRecorder) {
- m.CheckVPC(gomock.Any(), "vpc-1234acbd").Return(nil)
- m.GetSubNets(gomock.Any(), "vpc-1234acbd").Return([]awsResource{
- existingAWSResource{id: "subnet1"},
- existingAWSResource{id: "subnet2"},
- }, nil)
- m.IsPublicSubnet(gomock.Any(), "subnet1").Return(true, nil)
- m.IsPublicSubnet(gomock.Any(), "subnet2").Return(true, nil)
- })
-}
-
-func convertYaml(t *testing.T, yaml string, assertErr error, fn ...func(m *MockAPIMockRecorder)) *cloudformation.Template {
+func convertYaml(t *testing.T, yaml string, assertErr error, fn ...func(m *sdk)) *cloudformation.Template {
project := loadConfig(t, yaml)
- ctrl := gomock.NewController(t)
- defer ctrl.Finish()
- m := NewMockAPI(ctrl)
+ m := sdk{}
for _, f := range fn {
- f(m.EXPECT())
+ f(&m)
}
- backend := &ComposeECS{
- aws: m,
- }
- template, err := backend.convert(context.TODO(), project)
+ template, err := convert(project)
if assertErr == nil {
assert.NilError(t, err)
} else {
@@ -610,7 +351,7 @@ func loadConfig(t *testing.T, yaml string) *types.Project {
{Config: dict},
},
}, func(options *loader.Options) {
- options.Name = t.Name()
+ options.SetProjectName(t.Name(), true)
})
assert.NilError(t, err)
return model
@@ -625,17 +366,3 @@ func getMainContainer(def *ecs.TaskDefinition, t *testing.T) ecs.TaskDefinition_
t.Fail()
return def.ContainerDefinitions[0]
}
-
-func useDefaultVPC(m *MockAPIMockRecorder) {
- m.GetDefaultVPC(gomock.Any()).Return("vpc-123", nil)
- m.GetSubNets(gomock.Any(), "vpc-123").Return([]awsResource{
- existingAWSResource{id: "subnet1"},
- existingAWSResource{id: "subnet2"},
- }, nil)
- m.IsPublicSubnet(gomock.Any(), "subnet1").Return(true, nil)
- m.IsPublicSubnet(gomock.Any(), "subnet2").Return(true, nil)
-}
-
-func useGPU(m *MockAPIMockRecorder) {
- m.GetParameter(gomock.Any(), gomock.Any()).Return("", nil)
-}
diff --git a/ecs/compatibility.go b/ecs/compatibility.go
deleted file mode 100644
index 44801ce4..00000000
--- a/ecs/compatibility.go
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "fmt"
-
- "github.com/compose-spec/compose-go/compatibility"
- "github.com/compose-spec/compose-go/errdefs"
- "github.com/compose-spec/compose-go/types"
- "github.com/sirupsen/logrus"
-)
-
-func (b *ComposeECS) checkCompatibility(project *types.Project) error {
- var checker compatibility.Checker = &fargateCompatibilityChecker{
- AllowList: compatibility.AllowList{
- Supported: compatibleComposeAttributes,
- },
- projet: project,
- }
- compatibility.Check(project, checker)
- for _, err := range checker.Errors() {
- if errdefs.IsIncompatibleError(err) {
- return err
- }
- logrus.Warn(err.Error())
- }
- if !compatibility.IsCompatible(checker) {
- return fmt.Errorf("compose file is incompatible with Amazon ECS")
- }
- return nil
-}
-
-type fargateCompatibilityChecker struct {
- compatibility.AllowList
- projet *types.Project
-}
-
-var compatibleComposeAttributes = []string{
- "services.command",
- "services.container_name",
- "services.cap_drop",
- "services.depends_on",
- "services.deploy",
- "services.deploy.placement",
- "services.deploy.placement.constraints",
- "services.deploy.replicas",
- "services.deploy.resources.limits",
- "services.deploy.resources.limits.cpus",
- "services.deploy.resources.limits.memory",
- "services.deploy.resources.reservations",
- "services.deploy.resources.reservations.cpus",
- "services.deploy.resources.reservations.memory",
- "services.deploy.resources.reservations.devices",
- "services.deploy.resources.reservations.devices.capabilities",
- "services.deploy.resources.reservations.devices.count",
- "services.deploy.resources.reservations.devices.driver",
- "services.deploy.resources.reservations.generic_resources",
- "services.deploy.resources.reservations.generic_resources.discrete_resource_spec",
- "services.deploy.update_config",
- "services.deploy.update_config.parallelism",
- "services.entrypoint",
- "services.environment",
- "services.env_file",
- "services.healthcheck",
- "services.healthcheck.interval",
- "services.healthcheck.retries",
- "services.healthcheck.start_period",
- "services.healthcheck.test",
- "services.healthcheck.timeout",
- "services.image",
- "services.init",
- "services.labels",
- "services.logging",
- "services.logging.options",
- "services.networks",
- "services.ports",
- "services.ports.mode",
- "services.ports.target",
- "services.ports.protocol",
- "services.scale",
- "services.secrets",
- "services.secrets.source",
- "services.secrets.target",
- "services.user",
- "services.volumes",
- "services.volumes.read_only",
- "services.volumes.target",
- "services.working_dir",
- "secrets.external",
- "secrets.name",
- "secrets.file",
- "volumes",
- "volumes.external",
- "volumes.name",
- "volumes.driver_opts",
- "networks.external",
- "networks.name",
-}
-
-func (c *fargateCompatibilityChecker) CheckImage(service *types.ServiceConfig) {
- if service.Image == "" {
- c.Incompatible("service %s doesn't define a Docker image to run", service.Name)
- }
-}
-
-func (c *fargateCompatibilityChecker) CheckPortsPublished(p *types.ServicePortConfig) {
- if p.Published == 0 {
- p.Published = p.Target
- }
- if p.Published != p.Target {
- c.Incompatible("published port can't be set to a distinct value than container port")
- }
-}
-
-func (c *fargateCompatibilityChecker) CheckVolumesSource(config *types.ServiceVolumeConfig) {
- if config.Type == types.VolumeTypeBind {
- c.Incompatible("ECS Fargate does not support bind mounts from host")
- }
- if config.Type == types.VolumeTypeTmpfs {
- c.Incompatible("ECS Fargate does not support tmpfs")
- }
-}
-
-func (c *fargateCompatibilityChecker) CheckCapAdd(service *types.ServiceConfig) {
- add := []string{}
- for _, cap := range service.CapAdd {
- switch cap {
- case "SYS_PTRACE":
- add = append(add, cap)
- default:
- c.Incompatible("ECS doesn't allow to add capability %s", cap)
- }
- }
- service.CapAdd = add
-}
-
-func (c *fargateCompatibilityChecker) CheckLoggingDriver(config *types.LoggingConfig) {
- if config.Driver != "" && config.Driver != "awslogs" {
- c.Unsupported("services.logging.driver %s is not supported", config.Driver)
- }
-}
-
-func (c *fargateCompatibilityChecker) CheckUlimits(service *types.ServiceConfig) {
- for k := range service.Ulimits {
- if k != "nofile" {
- c.Unsupported("services.ulimits.%s is not supported by Fargate", k)
- delete(service.Ulimits, k)
- }
- }
-}
-
-func (c *fargateCompatibilityChecker) CheckDeployResourcesDevicesCapabilities(s string, r types.DeviceRequest) {
- for _, cap := range r.Capabilities {
- if cap != "gpu" {
- c.Unsupported("services.deploy.resources.%s.devices.capabilities = %s", s, cap)
- }
- }
-}
-
-func (c *fargateCompatibilityChecker) CheckDeployResourcesDevicesDriver(s string, r types.DeviceRequest) {
- if r.Driver != "" && r.Driver != "nvidia" {
- c.Unsupported("services.deploy.resources.%s.devices.driver = %s", s, r.Driver)
- }
-}
diff --git a/ecs/convert.go b/ecs/convert.go
deleted file mode 100644
index 01ab0beb..00000000
--- a/ecs/convert.go
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- "sort"
- "strconv"
- "strings"
- "time"
-
- "github.com/docker/compose-ecs/ecs/secrets"
-
- ecsapi "github.com/aws/aws-sdk-go/service/ecs"
- "github.com/awslabs/goformation/v4/cloudformation"
- "github.com/awslabs/goformation/v4/cloudformation/ecs"
- "github.com/compose-spec/compose-go/types"
- "github.com/docker/cli/opts"
- "github.com/joho/godotenv"
-)
-
-const secretsInitContainerImage = "docker/ecs-secrets-sidecar:1.0"
-const searchDomainInitContainerImage = "docker/ecs-searchdomain-sidecar:1.0"
-
-func (b *ComposeECS) createTaskDefinition(project *types.Project, service types.ServiceConfig, resources awsResources) (*ecs.TaskDefinition, error) {
- cpu, mem, err := toLimits(service)
- if err != nil {
- return nil, err
- }
- _, memReservation := toContainerReservation(service)
- credential := getRepoCredentials(service)
-
- logConfiguration := getLogConfiguration(service, project)
-
- var (
- initContainers []ecs.TaskDefinition_ContainerDefinition
- volumes []ecs.TaskDefinition_Volume
- mounts []ecs.TaskDefinition_MountPoint
- )
- if len(service.Secrets) > 0 {
- secretsVolume, secretsMount, secretsSideCar, err := createSecretsSideCar(project, service, logConfiguration)
- if err != nil {
- return nil, err
- }
- initContainers = append(initContainers, secretsSideCar)
- volumes = append(volumes, secretsVolume)
- mounts = append(mounts, secretsMount)
- }
-
- initContainers = append(initContainers, ecs.TaskDefinition_ContainerDefinition{
- Name: fmt.Sprintf("%s_ResolvConf_InitContainer", normalizeResourceName(service.Name)),
- Image: searchDomainInitContainerImage,
- Essential: false,
- Command: []string{b.Region + ".compute.internal", project.Name + ".local"},
- LogConfiguration: logConfiguration,
- })
-
- var dependencies []ecs.TaskDefinition_ContainerDependency
- for _, c := range initContainers {
- dependencies = append(dependencies, ecs.TaskDefinition_ContainerDependency{
- Condition: ecsapi.ContainerConditionSuccess,
- ContainerName: c.Name,
- })
- }
-
- for _, v := range service.Volumes {
- n := fmt.Sprintf("%sAccessPoint", normalizeResourceName(v.Source))
- volumes = append(volumes, ecs.TaskDefinition_Volume{
- EFSVolumeConfiguration: &ecs.TaskDefinition_EFSVolumeConfiguration{
- AuthorizationConfig: &ecs.TaskDefinition_AuthorizationConfig{
- AccessPointId: cloudformation.Ref(n),
- IAM: "ENABLED",
- },
- FilesystemId: resources.filesystems[v.Source].ID(),
- TransitEncryption: "ENABLED",
- },
- Name: v.Source,
- })
- mounts = append(mounts, ecs.TaskDefinition_MountPoint{
- ContainerPath: v.Target,
- ReadOnly: v.ReadOnly,
- SourceVolume: v.Source,
- })
- }
-
- pairs, err := createEnvironment(project, service)
- if err != nil {
- return nil, err
- }
- var reservations *types.Resource
- if service.Deploy != nil && service.Deploy.Resources.Reservations != nil {
- reservations = service.Deploy.Resources.Reservations
- }
-
- containers := append(initContainers, ecs.TaskDefinition_ContainerDefinition{
- Command: service.Command,
- DisableNetworking: service.NetworkMode == "none",
- DependsOnProp: dependencies,
- DnsSearchDomains: service.DNSSearch,
- DnsServers: service.DNS,
- DockerLabels: service.Labels,
- DockerSecurityOptions: service.SecurityOpt,
- EntryPoint: service.Entrypoint,
- Environment: pairs,
- Essential: true,
- ExtraHosts: toHostEntryPtr(service.ExtraHosts),
- FirelensConfiguration: nil,
- HealthCheck: toHealthCheck(service.HealthCheck),
- Hostname: service.Hostname,
- Image: service.Image,
- Interactive: false,
- Links: nil,
- LinuxParameters: toLinuxParameters(service),
- LogConfiguration: logConfiguration,
- MemoryReservation: memReservation,
- MountPoints: mounts,
- Name: service.Name,
- PortMappings: toPortMappings(service.Ports),
- Privileged: service.Privileged,
- PseudoTerminal: service.Tty,
- ReadonlyRootFilesystem: service.ReadOnly,
- RepositoryCredentials: credential,
- ResourceRequirements: toTaskResourceRequirements(reservations),
- StartTimeout: 0,
- StopTimeout: durationToInt(service.StopGracePeriod),
- SystemControls: toSystemControls(service.Sysctls),
- Ulimits: toUlimits(service.Ulimits),
- User: service.User,
- VolumesFrom: nil,
- WorkingDirectory: service.WorkingDir,
- })
-
- launchType := ecsapi.LaunchTypeFargate
- if requireEC2(service) {
- launchType = ecsapi.LaunchTypeEc2
- }
-
- return &ecs.TaskDefinition{
- ContainerDefinitions: containers,
- Cpu: cpu,
- Family: fmt.Sprintf("%s-%s", project.Name, service.Name),
- IpcMode: service.Ipc,
- Memory: mem,
- NetworkMode: ecsapi.NetworkModeAwsvpc, // FIXME could be set by service.NetworkMode, Fargate only supports network mode ‘awsvpc’.
- PidMode: service.Pid,
- PlacementConstraints: toPlacementConstraints(service.Deploy),
- ProxyConfiguration: nil,
- RequiresCompatibilities: []string{
- launchType,
- },
- Volumes: volumes,
- }, nil
-}
-
-func toTaskResourceRequirements(reservations *types.Resource) []ecs.TaskDefinition_ResourceRequirement {
- if reservations == nil {
- return nil
- }
- var requirements []ecs.TaskDefinition_ResourceRequirement
- for _, r := range reservations.GenericResources {
- if r.DiscreteResourceSpec.Kind == "gpus" {
- requirements = append(requirements, ecs.TaskDefinition_ResourceRequirement{
- Type: ecsapi.ResourceTypeGpu,
- Value: fmt.Sprint(r.DiscreteResourceSpec.Value),
- })
- }
- }
- for _, r := range reservations.Devices {
- hasGpuCap := false
- for _, c := range r.Capabilities {
- if c == "gpu" {
- hasGpuCap = true
- break
- }
- }
- if hasGpuCap {
- count := r.Count
- if count <= 0 {
- count = 1
- }
- requirements = append(requirements, ecs.TaskDefinition_ResourceRequirement{
- Type: ecsapi.ResourceTypeGpu,
- Value: fmt.Sprint(count),
- })
- }
- }
- return requirements
-}
-
-func createSecretsSideCar(project *types.Project, service types.ServiceConfig, logConfiguration *ecs.TaskDefinition_LogConfiguration) (
- ecs.TaskDefinition_Volume,
- ecs.TaskDefinition_MountPoint,
- ecs.TaskDefinition_ContainerDefinition,
- error) {
- initContainerName := fmt.Sprintf("%s_Secrets_InitContainer", normalizeResourceName(service.Name))
- secretsVolume := ecs.TaskDefinition_Volume{
- Name: "secrets",
- }
- secretsMount := ecs.TaskDefinition_MountPoint{
- ContainerPath: "/run/secrets/",
- ReadOnly: true,
- SourceVolume: "secrets",
- }
-
- var (
- args []secrets.Secret
- taskSecrets []ecs.TaskDefinition_Secret
- )
- for _, s := range service.Secrets {
- secretConfig := project.Secrets[s.Source]
- if s.Target == "" {
- s.Target = s.Source
- }
- taskSecrets = append(taskSecrets, ecs.TaskDefinition_Secret{
- Name: s.Target,
- ValueFrom: secretConfig.Name,
- })
- var keys []string
- if ext, ok := secretConfig.Extensions[extensionKeys]; ok {
- if key, ok := ext.(string); ok {
- keys = append(keys, key)
- } else {
- for _, k := range ext.([]interface{}) {
- keys = append(keys, k.(string))
- }
- }
- }
- args = append(args, secrets.Secret{
- Name: s.Target,
- Keys: keys,
- })
- }
- command, err := json.Marshal(args)
- if err != nil {
- return ecs.TaskDefinition_Volume{}, ecs.TaskDefinition_MountPoint{}, ecs.TaskDefinition_ContainerDefinition{}, err
- }
- secretsSideCar := ecs.TaskDefinition_ContainerDefinition{
- Name: initContainerName,
- Image: secretsInitContainerImage,
- Command: []string{string(command)},
- Essential: false, // FIXME this will be ignored, see https://github.com/awslabs/goformation/issues/61#issuecomment-625139607
- LogConfiguration: logConfiguration,
- MountPoints: []ecs.TaskDefinition_MountPoint{
- {
- ContainerPath: "/run/secrets/",
- ReadOnly: false,
- SourceVolume: "secrets",
- },
- },
- Secrets: taskSecrets,
- }
- return secretsVolume, secretsMount, secretsSideCar, nil
-}
-
-func createEnvironment(project *types.Project, service types.ServiceConfig) ([]ecs.TaskDefinition_KeyValuePair, error) {
- environment := map[string]*string{}
- for _, f := range service.EnvFile {
- if !filepath.IsAbs(f) {
- f = filepath.Join(project.WorkingDir, f)
- }
- if _, err := os.Stat(f); os.IsNotExist(err) {
- return nil, err
- }
- file, err := os.Open(f)
- if err != nil {
- return nil, err
- }
- defer file.Close() // nolint:errcheck
-
- env, err := godotenv.Parse(file)
- if err != nil {
- return nil, err
- }
- for k, v := range env {
- environment[k] = &v
- }
- }
- for k, v := range service.Environment {
- environment[k] = v
- }
-
- var pairs []ecs.TaskDefinition_KeyValuePair
- for k, v := range environment {
- name := k
- var value string
- if v != nil {
- value = *v
- }
- pairs = append(pairs, ecs.TaskDefinition_KeyValuePair{
- Name: name,
- Value: value,
- })
- }
-
- //order env keys for idempotence between calls
- //to avoid unnecessary resource recreations on CloudFormation
- sort.Slice(pairs, func(i, j int) bool {
- return pairs[i].Name < pairs[j].Name
- })
-
- return pairs, nil
-}
-
-func getLogConfiguration(service types.ServiceConfig, project *types.Project) *ecs.TaskDefinition_LogConfiguration {
- options := map[string]string{
- "awslogs-region": cloudformation.Ref("AWS::Region"),
- "awslogs-group": cloudformation.Ref("LogGroup"),
- "awslogs-stream-prefix": project.Name,
- }
- if service.Logging != nil {
- for k, v := range service.Logging.Options {
- if strings.HasPrefix(k, "awslogs-") {
- options[k] = v
- }
- }
- }
- logConfiguration := &ecs.TaskDefinition_LogConfiguration{
- LogDriver: ecsapi.LogDriverAwslogs,
- Options: options,
- }
- return logConfiguration
-}
-
-func toSystemControls(sysctls types.Mapping) []ecs.TaskDefinition_SystemControl {
- sys := []ecs.TaskDefinition_SystemControl{}
- for k, v := range sysctls {
- sys = append(sys, ecs.TaskDefinition_SystemControl{
- Namespace: k,
- Value: v,
- })
- }
- return sys
-}
-
-const miB = 1024 * 1024
-
-func toLimits(service types.ServiceConfig) (string, string, error) {
- mem, cpu, err := getConfiguredLimits(service)
- if err != nil {
- return "", "", err
- }
- if requireEC2(service) {
- // just return configured limits expressed in Mb and CPU units
- var cpuLimit, memLimit string
- if cpu > 0 {
- cpuLimit = fmt.Sprint(cpu)
- }
- if mem > 0 {
- memLimit = fmt.Sprint(mem / miB)
- }
- return cpuLimit, memLimit, nil
- }
-
- // All possible cpu/mem values for Fargate
- fargateCPUToMem := map[int64][]types.UnitBytes{
- 256: {512, 1024, 2048},
- 512: {1024, 2048, 3072, 4096},
- 1024: {2048, 3072, 4096, 5120, 6144, 7168, 8192},
- 2048: {4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360, 16384},
- 4096: {8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360, 16384, 17408, 18432, 19456, 20480, 21504, 22528, 23552, 24576, 25600, 26624, 27648, 28672, 29696, 30720},
- }
- cpuLimit := "256"
- memLimit := "512"
- if mem == 0 && cpu == 0 {
- return cpuLimit, memLimit, nil
- }
-
- var cpus []int64
- for k := range fargateCPUToMem {
- cpus = append(cpus, k)
- }
- sort.Slice(cpus, func(i, j int) bool { return cpus[i] < cpus[j] })
-
- for _, fargateCPU := range cpus {
- options := fargateCPUToMem[fargateCPU]
- if cpu <= fargateCPU {
- for _, m := range options {
- if mem <= m*miB {
- cpuLimit = strconv.FormatInt(fargateCPU, 10)
- memLimit = strconv.FormatInt(int64(m), 10)
- return cpuLimit, memLimit, nil
- }
- }
- }
- }
- return "", "", fmt.Errorf("the resources requested are not supported by ECS/Fargate")
-}
-
-func getConfiguredLimits(service types.ServiceConfig) (types.UnitBytes, int64, error) {
- if service.Deploy == nil {
- return 0, 0, nil
- }
-
- limits := service.Deploy.Resources.Limits
- if limits == nil {
- limits = service.Deploy.Resources.Reservations
- }
- if limits == nil {
- return 0, 0, nil
- }
-
- if limits.NanoCPUs == "" {
- return limits.MemoryBytes, 0, nil
- }
- v, err := opts.ParseCPUs(limits.NanoCPUs)
- if err != nil {
- return 0, 0, err
- }
-
- return limits.MemoryBytes, v / 1e6, nil
-}
-
-func toContainerReservation(service types.ServiceConfig) (string, int) {
- cpuReservation := ".0"
- memReservation := 0
-
- if service.Deploy == nil {
- return cpuReservation, memReservation
- }
-
- reservations := service.Deploy.Resources.Reservations
- if reservations == nil {
- return cpuReservation, memReservation
- }
- return reservations.NanoCPUs, int(reservations.MemoryBytes / miB)
-}
-
-func toPlacementConstraints(deploy *types.DeployConfig) []ecs.TaskDefinition_TaskDefinitionPlacementConstraint {
- if deploy == nil || deploy.Placement.Constraints == nil || len(deploy.Placement.Constraints) == 0 {
- return nil
- }
- pl := []ecs.TaskDefinition_TaskDefinitionPlacementConstraint{}
- for _, c := range deploy.Placement.Constraints {
- pl = append(pl, ecs.TaskDefinition_TaskDefinitionPlacementConstraint{
- Expression: c,
- Type: "",
- })
- }
- return pl
-}
-
-func toPortMappings(ports []types.ServicePortConfig) []ecs.TaskDefinition_PortMapping {
- if len(ports) == 0 {
- return nil
- }
- m := []ecs.TaskDefinition_PortMapping{}
- for _, p := range ports {
- m = append(m, ecs.TaskDefinition_PortMapping{
- ContainerPort: int(p.Target),
- HostPort: int(p.Published),
- Protocol: p.Protocol,
- })
- }
- return m
-}
-
-func toUlimits(ulimits map[string]*types.UlimitsConfig) []ecs.TaskDefinition_Ulimit {
- if len(ulimits) == 0 {
- return nil
- }
- u := []ecs.TaskDefinition_Ulimit{}
- for k, v := range ulimits {
- u = append(u, ecs.TaskDefinition_Ulimit{
- Name: k,
- SoftLimit: v.Soft,
- HardLimit: v.Hard,
- })
- }
- return u
-}
-
-func toLinuxParameters(service types.ServiceConfig) *ecs.TaskDefinition_LinuxParameters {
- return &ecs.TaskDefinition_LinuxParameters{
- Capabilities: toKernelCapabilities(service.CapAdd, service.CapDrop),
- Devices: nil,
- InitProcessEnabled: service.Init != nil && *service.Init,
- MaxSwap: 0,
- // FIXME SharedMemorySize: service.ShmSize,
- Swappiness: 0,
- Tmpfs: toTmpfs(service.Tmpfs),
- }
-}
-
-func toTmpfs(tmpfs types.StringList) []ecs.TaskDefinition_Tmpfs {
- if len(tmpfs) == 0 {
- return nil
- }
- o := []ecs.TaskDefinition_Tmpfs{}
- for _, path := range tmpfs {
- o = append(o, ecs.TaskDefinition_Tmpfs{
- ContainerPath: path,
- Size: 100, // size is required on ECS, unlimited by the compose spec
- })
- }
- return o
-}
-
-func toKernelCapabilities(add []string, drop []string) *ecs.TaskDefinition_KernelCapabilities {
- if len(add) == 0 && len(drop) == 0 {
- return nil
- }
- return &ecs.TaskDefinition_KernelCapabilities{
- Add: add,
- Drop: drop,
- }
-
-}
-
-func toHealthCheck(check *types.HealthCheckConfig) *ecs.TaskDefinition_HealthCheck {
- if check == nil {
- return nil
- }
- retries := 0
- if check.Retries != nil {
- retries = int(*check.Retries)
- }
- return &ecs.TaskDefinition_HealthCheck{
- Command: check.Test,
- Interval: durationToInt(check.Interval),
- Retries: retries,
- StartPeriod: durationToInt(check.StartPeriod),
- Timeout: durationToInt(check.Timeout),
- }
-}
-
-func durationToInt(interval *types.Duration) int {
- if interval == nil {
- return 0
- }
- v := int(time.Duration(*interval).Seconds())
- return v
-}
-
-func toHostEntryPtr(hosts types.HostsList) []ecs.TaskDefinition_HostEntry {
- if len(hosts) == 0 {
- return nil
- }
- e := []ecs.TaskDefinition_HostEntry{}
- for _, h := range hosts {
- parts := strings.SplitN(h, ":", 2) // FIXME this should be handled by compose-go
- e = append(e, ecs.TaskDefinition_HostEntry{
- Hostname: parts[0],
- IpAddress: parts[1],
- })
- }
- return e
-}
-
-func getRepoCredentials(service types.ServiceConfig) *ecs.TaskDefinition_RepositoryCredentials {
- if value, ok := service.Extensions[extensionPullCredentials]; ok {
- return &ecs.TaskDefinition_RepositoryCredentials{CredentialsParameter: value.(string)}
- }
- return nil
-}
-
-func requireEC2(s types.ServiceConfig) bool {
- return gpuRequirements(s) > 0
-}
-
-func gpuRequirements(s types.ServiceConfig) int64 {
- if deploy := s.Deploy; deploy != nil {
- if reservations := deploy.Resources.Reservations; reservations != nil {
- for _, resource := range reservations.GenericResources {
- if resource.DiscreteResourceSpec.Kind == "gpus" {
- return resource.DiscreteResourceSpec.Value
- }
- }
- for _, device := range reservations.Devices {
- if len(device.Capabilities) == 1 && device.Capabilities[0] == "gpu" {
- return device.Count
- }
- }
- }
- }
- return 0
-}
diff --git a/ecs/doc.go b/ecs/doc.go
deleted file mode 100644
index 4fe32bd6..00000000
--- a/ecs/doc.go
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
diff --git a/ecs/down.go b/ecs/down.go
deleted file mode 100644
index f684675e..00000000
--- a/ecs/down.go
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
-
- "github.com/docker/compose/v2/pkg/api"
- "github.com/docker/compose/v2/pkg/progress"
-
- "github.com/docker/compose-ecs/utils"
-)
-
-func (b *ComposeECS) Down(ctx context.Context, projectName string, options api.DownOptions) error {
- if err := checkUnsupportedDownOptions(ctx, options); err != nil {
- return err
- }
- return progress.Run(ctx, func(ctx context.Context) error {
- return b.down(ctx, projectName)
- })
-}
-
-func (b *ComposeECS) down(ctx context.Context, projectName string) error {
- resources, err := b.aws.ListStackResources(ctx, projectName)
- if err != nil {
- return err
- }
-
- err = resources.apply(awsTypeCapacityProvider, doDelete(ctx, b.aws.DeleteCapacityProvider))
- if err != nil {
- return err
- }
-
- err = resources.apply(awsTypeAutoscalingGroup, doDelete(ctx, b.aws.DeleteAutoscalingGroup))
- if err != nil {
- return err
- }
-
- previousEvents, err := b.previousStackEvents(ctx, projectName)
- if err != nil {
- return err
- }
-
- err = b.aws.DeleteStack(ctx, projectName)
- if err != nil {
- return err
- }
- return b.WaitStackCompletion(ctx, projectName, stackDelete, previousEvents...)
-}
-
-func (b *ComposeECS) previousStackEvents(ctx context.Context, project string) ([]string, error) {
- events, err := b.aws.DescribeStackEvents(ctx, project)
- if err != nil {
- return nil, err
- }
- var previousEvents []string
- for _, e := range events {
- previousEvents = append(previousEvents, *e.EventId)
- }
- return previousEvents, nil
-}
-
-func doDelete(ctx context.Context, delete func(ctx context.Context, arn string) error) func(r stackResource) error {
- return func(r stackResource) error {
- w := progress.ContextWriter(ctx)
- w.Event(progress.RemovingEvent(r.LogicalID))
- err := delete(ctx, r.ARN)
- if err != nil {
- w.Event(progress.ErrorEvent(r.LogicalID))
- return err
- }
- w.Event(progress.RemovedEvent(r.LogicalID))
- return nil
- }
-}
-
-func checkUnsupportedDownOptions(ctx context.Context, o api.DownOptions) error {
- var errs error
- checks := []struct {
- toCheck, expected interface{}
- option string
- }{
- {o.Volumes, false, "volumes"},
- {o.Images, "", "images"},
- {o.RemoveOrphans, false, "remove-orphans"},
- {o.Timeout, nil, "timeout"},
- }
- for _, c := range checks {
- errs = utils.CheckUnsupported(ctx, errs, c.toCheck, c.expected, "down", c.option)
- }
-
- return errs
-}
diff --git a/ecs/e2e/ecs/compose.yaml b/ecs/e2e/ecs/compose.yaml
index 84961fe3..7162286c 100644
--- a/ecs/e2e/ecs/compose.yaml
+++ b/ecs/e2e/ecs/compose.yaml
@@ -5,20 +5,23 @@ services:
words:
image: gtardif/sentences-api
ports:
- - "8080:8080"
+ - 8080
+
web:
image: gtardif/sentences-web
ports:
- - "80:80"
+ - 80
+
websecrets:
- image: dockerinternal/e2e_test_secret_server
- ports:
- - "90:90"
environment:
- - "PORT=90"
+ PORT: 90
+ image: dockerinternal/e2e_test_secret_server
+ ports:
+ - 90
secrets:
- - mysecret1
+ - some_secret
secrets:
- mysecret1:
- file: ./my_secret1.txt
+ some_secret:
+ external: true
+ name: arn:aws:secretsmanager:us-east-1:1234:secret:some_secret
diff --git a/ecs/e2e/ecs/e2e-ecs_test.go b/ecs/e2e/ecs/e2e-ecs_test.go
index 0e5d8813..390f5dbb 100644
--- a/ecs/e2e/ecs/e2e-ecs_test.go
+++ b/ecs/e2e/ecs/e2e-ecs_test.go
@@ -1,28 +1,10 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 main
import (
"fmt"
"io"
"net/http"
- "os"
"path/filepath"
- "strconv"
"strings"
"testing"
"time"
@@ -32,37 +14,6 @@ import (
"gotest.tools/v3/poll"
)
-func TestSecrets(t *testing.T) {
- startTime := strconv.Itoa(int(time.Now().UnixNano()))
- secretName := "secret" + strings.ToLower(t.Name()) + startTime
- t.Run("create secret", func(t *testing.T) {
- secretFile := filepath.Join(t.TempDir(), "secret.txt")
- err := os.WriteFile(secretFile, []byte("pass1"), 0644)
- assert.Check(t, err == nil)
- res := icmd.RunCommand(composeECS(), "secret", "create", secretName, secretFile)
- stdout := res.Stdout()
- stderr := res.Stderr()
- fmt.Println(stderr)
- assert.Check(t, strings.Contains(stdout, secretName), stdout)
- })
-
- t.Run("list secrets", func(t *testing.T) {
- res := icmd.RunCommand(composeECS(), "secret", "list")
- assert.Check(t, strings.Contains(res.Stdout(), secretName), res.Stdout())
- })
-
- t.Run("inspect secret", func(t *testing.T) {
- res := icmd.RunCommand(composeECS(), "secret", "inspect", secretName)
- assert.Check(t, strings.Contains(res.Stdout(), `"Name": "`+secretName+`"`), res.Stdout())
- })
-
- t.Run("rm secret", func(t *testing.T) {
- icmd.RunCommand(composeECS(), "secret", "rm", secretName)
- res := icmd.RunCommand("secret", "list")
- assert.Check(t, !strings.Contains(res.Stdout(), secretName), res.Stdout())
- })
-}
-
func TestCompose(t *testing.T) {
t.Run("compose-ecs up", func(t *testing.T) {
res := icmd.RunCommand(composeECS(), "up")
diff --git a/ecs/e2e/ecs/my_secret1.txt b/ecs/e2e/ecs/my_secret1.txt
deleted file mode 100644
index 73a420f3..00000000
--- a/ecs/e2e/ecs/my_secret1.txt
+++ /dev/null
@@ -1 +0,0 @@
-myPassword1
diff --git a/ecs/ec2.go b/ecs/ec2.go
deleted file mode 100644
index fa6fb9f6..00000000
--- a/ecs/ec2.go
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
- "encoding/base64"
- "fmt"
- "strings"
-
- "github.com/awslabs/goformation/v4/cloudformation"
- "github.com/awslabs/goformation/v4/cloudformation/autoscaling"
- "github.com/awslabs/goformation/v4/cloudformation/ecs"
- "github.com/awslabs/goformation/v4/cloudformation/iam"
- "github.com/compose-spec/compose-go/types"
-)
-
-const (
- placementConstraintAMI = "node.ami == "
- placementConstraintMachine = "node.machine == "
-)
-
-func (b *ComposeECS) createCapacityProvider(ctx context.Context, project *types.Project, template *cloudformation.Template, resources awsResources) error {
- var (
- ec2 bool
- ami string
- machineType string
- )
- for _, service := range project.Services {
- if requireEC2(service) {
- ec2 = true
- // TODO once we can assign a service to a CapacityProvider, we could run this _per service_
- ami, machineType = getUserDefinedMachine(service)
- break
- }
- }
-
- if !ec2 {
- return nil
- }
-
- if ami == "" {
- recommended, err := b.aws.GetParameter(ctx, "/aws/service/ecs/optimized-ami/amazon-linux-2/gpu/recommended")
- if err != nil {
- return err
- }
- ami = recommended
- }
-
- if machineType == "" {
- t, err := guessMachineType(project)
- if err != nil {
- return err
- }
- machineType = t
- }
-
- template.Resources["CapacityProvider"] = &ecs.CapacityProvider{
- AutoScalingGroupProvider: &ecs.CapacityProvider_AutoScalingGroupProvider{
- AutoScalingGroupArn: cloudformation.Ref("AutoscalingGroup"),
- ManagedScaling: &ecs.CapacityProvider_ManagedScaling{
- TargetCapacity: 100,
- },
- },
- Tags: projectTags(project),
- }
-
- template.Resources["AutoscalingGroup"] = &autoscaling.AutoScalingGroup{
- LaunchConfigurationName: cloudformation.Ref("LaunchConfiguration"),
- MaxSize: "10", //TODO
- MinSize: "1",
- VPCZoneIdentifier: resources.subnetsIDs(),
- }
-
- userData := base64.StdEncoding.EncodeToString([]byte(
- fmt.Sprintf("#!/bin/bash\necho ECS_CLUSTER=%s >> /etc/ecs/ecs.config", project.Name)))
-
- template.Resources["LaunchConfiguration"] = &autoscaling.LaunchConfiguration{
- ImageId: ami,
- InstanceType: machineType,
- SecurityGroups: resources.allSecurityGroups(),
- IamInstanceProfile: cloudformation.Ref("EC2InstanceProfile"),
- UserData: userData,
- }
-
- template.Resources["EC2InstanceProfile"] = &iam.InstanceProfile{
- Roles: []string{cloudformation.Ref("EC2InstanceRole")},
- }
-
- template.Resources["EC2InstanceRole"] = &iam.Role{
- AssumeRolePolicyDocument: ec2InstanceAssumeRolePolicyDocument,
- ManagedPolicyArns: []string{
- ecsEC2InstanceRole,
- },
- Tags: projectTags(project),
- }
-
- cluster := template.Resources["Cluster"].(*ecs.Cluster)
- cluster.CapacityProviders = []string{
- cloudformation.Ref("CapacityProvider"),
- }
-
- return nil
-}
-
-func getUserDefinedMachine(s types.ServiceConfig) (ami string, machineType string) {
- if s.Deploy != nil {
- for _, s := range s.Deploy.Placement.Constraints {
- if strings.HasPrefix(s, placementConstraintAMI) {
- ami = s[len(placementConstraintAMI):]
- }
- if strings.HasPrefix(s, placementConstraintMachine) {
- machineType = s[len(placementConstraintMachine):]
- }
- }
- }
- return ami, machineType
-}
diff --git a/ecs/ec2_test.go b/ecs/ec2_test.go
deleted file mode 100644
index bd681981..00000000
--- a/ecs/ec2_test.go
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "testing"
-
- "github.com/awslabs/goformation/v4/cloudformation/autoscaling"
- "gotest.tools/v3/assert"
-)
-
-func TestUserDefinedAMI(t *testing.T) {
- template := convertYaml(t, `
-services:
- test:
- image: "image"
- deploy:
- placement:
- constraints:
- - "node.ami == ami123456789"
- - "node.machine == t0.femto"
- resources:
- # devices:
- # - capabilities: ["gpu"]
- reservations:
- memory: 8Gb
- generic_resources:
- - discrete_resource_spec:
- kind: gpus
- value: 1
-`, nil, useDefaultVPC)
- lc := template.Resources["LaunchConfiguration"].(*autoscaling.LaunchConfiguration)
- assert.Check(t, lc.ImageId == "ami123456789")
- assert.Check(t, lc.InstanceType == "t0.femto")
-}
diff --git a/ecs/gpu.go b/ecs/gpu.go
deleted file mode 100644
index a5f0386f..00000000
--- a/ecs/gpu.go
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "fmt"
- "math"
- "strconv"
-
- "github.com/compose-spec/compose-go/types"
- "github.com/docker/go-units"
-)
-
-type machine struct {
- id string
- cpus float64
- memory types.UnitBytes
- gpus int64
-}
-
-type family []machine
-
-var gpufamily = family{
- {
- id: "g4dn.xlarge",
- cpus: 4,
- memory: 16 * units.GiB,
- gpus: 1,
- },
- {
- id: "g4dn.2xlarge",
- cpus: 8,
- memory: 32 * units.GiB,
- gpus: 1,
- },
- {
- id: "g4dn.4xlarge",
- cpus: 16,
- memory: 64 * units.GiB,
- gpus: 1,
- },
- {
- id: "g4dn.8xlarge",
- cpus: 32,
- memory: 128 * units.GiB,
- gpus: 1,
- },
- {
- id: "g4dn.12xlarge",
- cpus: 48,
- memory: 192 * units.GiB,
- gpus: 4,
- },
- {
- id: "g4dn.16xlarge",
- cpus: 64,
- memory: 256 * units.GiB,
- gpus: 1,
- },
- {
- id: "g4dn.metal",
- cpus: 96,
- memory: 384 * units.GiB,
- gpus: 8,
- },
-}
-
-type filterFn func(machine) bool
-
-func (f family) filter(fn filterFn) family {
- var filtered family
- for _, machine := range f {
- if fn(machine) {
- filtered = append(filtered, machine)
- }
- }
- return filtered
-}
-
-func (f family) firstOrError(msg string, args ...interface{}) (machine, error) {
- if len(f) == 0 {
- return machine{}, fmt.Errorf(msg, args...)
- }
- return f[0], nil
-}
-
-func guessMachineType(project *types.Project) (string, error) {
- // we select a machine type to match all gpus-bound services requirements
- // once https://github.com/aws/containers-roadmap/issues/631 is implemented we can define dedicated CapacityProviders per service.
- requirements, err := getResourceRequirements(project)
- if err != nil {
- return "", err
- }
-
- instanceType, err := gpufamily.
- filter(func(m machine) bool {
- return m.memory > requirements.memory // actual memory available for ECS tasks < total machine memory
- }).
- filter(func(m machine) bool {
- return m.cpus >= requirements.cpus
- }).
- filter(func(m machine) bool {
- return m.gpus >= requirements.gpus
- }).
- firstOrError("none of the Amazon EC2 G4 instance types meet the requirements for memory:%d cpu:%f gpus:%d", requirements.memory, requirements.cpus, requirements.gpus)
- if err != nil {
- return "", err
- }
- return instanceType.id, nil
-}
-
-type resourceRequirements struct {
- memory types.UnitBytes
- cpus float64
- gpus int64
-}
-
-func getResourceRequirements(project *types.Project) (*resourceRequirements, error) {
- return toResourceRequirementsSlice(project).
- filter(func(requirements *resourceRequirements) bool {
- return requirements != nil && requirements.gpus != 0
- }).
- max()
-}
-
-type eitherRequirementsOrError struct {
- requirements []*resourceRequirements
- err error
-}
-
-func toResourceRequirementsSlice(project *types.Project) eitherRequirementsOrError {
- var requirements []*resourceRequirements
- for _, service := range project.Services {
- r, err := toResourceRequirements(service)
- if err != nil {
- return eitherRequirementsOrError{nil, err}
- }
- requirements = append(requirements, r)
- }
- return eitherRequirementsOrError{requirements, nil}
-}
-
-func (r eitherRequirementsOrError) filter(fn func(*resourceRequirements) bool) eitherRequirementsOrError {
- if r.err != nil {
- return r
- }
- var requirements []*resourceRequirements
- for _, req := range r.requirements {
- if fn(req) {
- requirements = append(requirements, req)
- }
- }
- return eitherRequirementsOrError{requirements, nil}
-}
-
-func toResourceRequirements(service types.ServiceConfig) (*resourceRequirements, error) {
- if service.Deploy == nil {
- return nil, nil
- }
- reservations := service.Deploy.Resources.Reservations
- if reservations == nil {
- return nil, nil
- }
-
- var requiredGPUs int64
- for _, r := range reservations.GenericResources {
- if r.DiscreteResourceSpec.Kind == "gpus" {
- requiredGPUs = r.DiscreteResourceSpec.Value
- break
- }
- }
-
- for _, r := range reservations.Devices {
- requiresGpus := false
- for _, c := range r.Capabilities {
- if c == "gpu" {
- requiresGpus = true
- break
- }
- }
- if requiresGpus {
- requiredGPUs = r.Count
- if requiredGPUs <= 0 {
- requiredGPUs = 1
- }
- break
- }
- }
-
- var nanocpu float64
- if reservations.NanoCPUs != "" {
- v, err := strconv.ParseFloat(reservations.NanoCPUs, 64)
- if err != nil {
- return nil, err
- }
- nanocpu = v
- }
- return &resourceRequirements{
- memory: reservations.MemoryBytes,
- cpus: nanocpu,
- gpus: requiredGPUs,
- }, nil
-}
-
-func (r resourceRequirements) combine(o *resourceRequirements) resourceRequirements {
- if o == nil {
- return r
- }
- return resourceRequirements{
- memory: maxUnitBytes(r.memory, o.memory),
- cpus: math.Max(r.cpus, o.cpus),
- gpus: maxInt64(r.gpus, o.gpus),
- }
-}
-
-func (r eitherRequirementsOrError) max() (*resourceRequirements, error) {
- if r.err != nil {
- return nil, r.err
- }
- min := resourceRequirements{}
- for _, req := range r.requirements {
- min = min.combine(req)
- }
- return &min, nil
-}
-
-func maxInt64(a, b int64) int64 {
- if a > b {
- return a
- }
- return b
-}
-
-func maxUnitBytes(a, b types.UnitBytes) types.UnitBytes {
- if a > b {
- return a
- }
- return b
-}
diff --git a/ecs/gpu_test.go b/ecs/gpu_test.go
deleted file mode 100644
index c952633b..00000000
--- a/ecs/gpu_test.go
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "testing"
-)
-
-func TestGuessMachineType(t *testing.T) {
- tests := []struct {
- name string
- yaml string
- want string
- wantErr bool
- }{
- {
- name: "1-gpus",
- yaml: `
-services:
- learning:
- image: tensorflow/tensorflow:latest-gpus
- deploy:
- resources:
- reservations:
- generic_resources:
- - discrete_resource_spec:
- kind: gpus
- value: 1
-`,
- want: "g4dn.xlarge",
- wantErr: false,
- },
- {
- name: "4-gpus",
- yaml: `
-services:
- learning:
- image: tensorflow/tensorflow:latest-gpus
- deploy:
- resources:
- reservations:
- generic_resources:
- - discrete_resource_spec:
- kind: gpus
- value: 4
-`,
- want: "g4dn.12xlarge",
- wantErr: false,
- },
- {
- name: "1-gpus, high-memory",
- yaml: `
-services:
- learning:
- image: tensorflow/tensorflow:latest-gpus
- deploy:
- resources:
- reservations:
- memory: 300Gb
- generic_resources:
- - discrete_resource_spec:
- kind: gpus
- value: 2
-`,
- want: "g4dn.metal",
- wantErr: false,
- },
- {
- name: "1-gpus, high-cpu",
- yaml: `
-services:
- learning:
- image: tensorflow/tensorflow:latest-gpus
- deploy:
- resources:
- reservations:
- memory: 32Gb
- cpus: "32"
- generic_resources:
- - discrete_resource_spec:
- kind: gpus
- value: 2
-`,
- want: "g4dn.12xlarge",
- wantErr: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- project := loadConfig(t, tt.yaml)
- got, err := guessMachineType(project)
- if (err != nil) != tt.wantErr {
- t.Errorf("guessMachineType() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if got != tt.want {
- t.Errorf("guessMachineType() got = %v, want %v", got, tt.want)
- }
- })
- }
-}
diff --git a/ecs/iam.go b/ecs/iam.go
deleted file mode 100644
index f6b80ed2..00000000
--- a/ecs/iam.go
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "fmt"
-
- "github.com/awslabs/goformation/v4/cloudformation"
-)
-
-const (
- ecsTaskExecutionPolicy = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
- ecrReadOnlyPolicy = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
- ecsEC2InstanceRole = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
-
- actionGetSecretValue = "secretsmanager:GetSecretValue"
- actionGetParameters = "ssm:GetParameters"
- actionDecrypt = "kms:Decrypt"
- actionAutoScaling = "application-autoscaling:*"
- actionGetMetrics = "cloudwatch:GetMetricStatistics"
- actionDescribeService = "ecs:DescribeServices"
- actionUpdateService = "ecs:UpdateService"
-)
-
-var (
- ecsTaskAssumeRolePolicyDocument = policyDocument("ecs-tasks.amazonaws.com")
- ec2InstanceAssumeRolePolicyDocument = policyDocument("ec2.amazonaws.com")
- ausocalingAssumeRolePolicyDocument = policyDocument("application-autoscaling.amazonaws.com")
-)
-
-func policyDocument(service string) PolicyDocument {
- return PolicyDocument{
- Version: "2012-10-17", // https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_version.html
- Statement: []PolicyStatement{
- {
- Effect: "Allow",
- Principal: PolicyPrincipal{
- Service: service,
- },
- Action: []string{"sts:AssumeRole"},
- },
- },
- }
-}
-
-func volumeMountPolicyDocument(volume string, filesystem string) PolicyDocument {
- ap := fmt.Sprintf("%sAccessPoint", normalizeResourceName(volume))
- return PolicyDocument{
- Version: "2012-10-17", // https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_version.html
- Statement: []PolicyStatement{
- {
- Effect: "Allow",
- Resource: []string{
- filesystem,
- },
- Action: []string{
- "elasticfilesystem:ClientMount",
- "elasticfilesystem:ClientWrite",
- "elasticfilesystem:ClientRootAccess",
- },
- Condition: Condition{
- StringEquals: map[string]string{
- "elasticfilesystem:AccessPointArn": cloudformation.Ref(ap),
- },
- },
- },
- },
- }
-}
-
-// PolicyDocument describes an IAM policy document
-// could alternatively depend on https://github.com/kubernetes-sigs/cluster-api-provider-aws/blob/master/cmd/clusterawsadm/api/iam/v1alpha1/types.go
-type PolicyDocument struct {
- Version string `json:",omitempty"`
- Statement []PolicyStatement `json:",omitempty"`
-}
-
-// PolicyStatement describes an IAM policy statement
-type PolicyStatement struct {
- Effect string `json:",omitempty"`
- Action []string `json:",omitempty"`
- Principal PolicyPrincipal `json:",omitempty"`
- Resource []string `json:",omitempty"`
- Condition Condition `json:",omitempty"`
-}
-
-// PolicyPrincipal describes an IAM policy principal
-type PolicyPrincipal struct {
- Service string `json:",omitempty"`
-}
-
-// Condition is the map of all conditions in the statement entry.
-type Condition struct {
- StringEquals map[string]string `json:",omitempty"`
- Bool map[string]string `json:",omitempty"`
-}
diff --git a/ecs/list.go b/ecs/list.go
deleted file mode 100644
index 349e7e82..00000000
--- a/ecs/list.go
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
- "fmt"
-
- "github.com/docker/compose/v2/pkg/api"
-
- "github.com/docker/compose-ecs/utils"
-)
-
-func (b *ComposeECS) List(ctx context.Context, opts api.ListOptions) ([]api.Stack, error) {
- if err := checkUnsupportedListOptions(ctx, opts); err != nil {
- return nil, err
- }
- stacks, err := b.aws.ListStacks(ctx)
- if err != nil {
- return nil, err
- }
-
- for _, stack := range stacks {
- if stack.Status == api.STARTING {
- if err := b.checkStackState(ctx, stack.Name); err != nil {
- stack.Status = api.FAILED
- stack.Reason = err.Error()
- }
- }
- }
- return stacks, nil
-
-}
-
-func checkUnsupportedListOptions(ctx context.Context, o api.ListOptions) error {
- return utils.CheckUnsupported(ctx, nil, o.All, false, "ls", "all")
-}
-
-func (b *ComposeECS) checkStackState(ctx context.Context, name string) error {
- resources, err := b.aws.ListStackResources(ctx, name)
- if err != nil {
- return err
- }
- svcArns := []string{}
- svcNames := map[string]string{}
- var cluster string
- for _, r := range resources {
- if r.Type == "AWS::ECS::Cluster" {
- cluster = r.ARN
- continue
- }
- if r.Type == "AWS::ECS::Service" {
- if r.ARN == "" {
- continue
- }
- svcArns = append(svcArns, r.ARN)
- svcNames[r.ARN] = r.LogicalID
- }
- }
- if len(cluster) == 0 {
- cluster, err = b.aws.GetStackMetadataClusterID(ctx, name)
- if err != nil {
- return err
- }
- }
- if len(svcArns) == 0 {
- return nil
- }
- services, err := b.aws.GetServiceTaskDefinition(ctx, cluster, svcArns)
- if err != nil {
- return err
- }
- for service, taskDef := range services {
- if err := b.checkServiceState(ctx, cluster, service, taskDef); err != nil {
- return fmt.Errorf("%s %s", svcNames[service], err.Error())
- }
- }
- return nil
-}
-
-func (b *ComposeECS) checkServiceState(ctx context.Context, cluster string, service string, taskdef string) error {
- runningTasks, err := b.aws.GetServiceTasks(ctx, cluster, service, false)
- if err != nil {
- return err
- }
- if len(runningTasks) > 0 {
- return nil
- }
- stoppedTasks, err := b.aws.GetServiceTasks(ctx, cluster, service, true)
- if err != nil {
- return err
- }
- if len(stoppedTasks) == 0 {
- return nil
- }
- // filter tasks by task definition
- tasks := []string{}
- for _, t := range stoppedTasks {
- if t.TaskDefinitionArn != nil && *t.TaskDefinitionArn == taskdef {
- tasks = append(tasks, *t.TaskArn)
- }
- }
- if len(tasks) == 0 {
- return nil
- }
- reason, err := b.aws.GetTaskStoppedReason(ctx, cluster, tasks[0])
- if err != nil {
- return err
- }
- return fmt.Errorf("%s", reason)
-}
diff --git a/ecs/logs.go b/ecs/logs.go
deleted file mode 100644
index ce2d2956..00000000
--- a/ecs/logs.go
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
-
- "github.com/docker/compose/v2/pkg/api"
-
- "github.com/docker/compose-ecs/utils"
-)
-
-func (b *ComposeECS) Logs(ctx context.Context, projectName string, consumer api.LogConsumer, options api.LogOptions) error {
- if err := checkUnsupportedLogOptions(ctx, options); err != nil {
- return err
- }
- if len(options.Services) > 0 {
- consumer = utils.FilteredLogConsumer(consumer, options.Services)
- }
- err := b.aws.GetLogs(ctx, projectName, consumer.Log, options.Follow)
- return err
-}
-
-func checkUnsupportedLogOptions(ctx context.Context, o api.LogOptions) error {
- var errs error
- checks := []struct {
- toCheck, expected interface{}
- option string
- }{
- {o.Since, "", "since"},
- {o.Tail, "all", "tail"},
- {o.Timestamps, false, "timestamps"},
- {o.Until, "", "until"},
- }
- for _, c := range checks {
- errs = utils.CheckUnsupported(ctx, errs, c.toCheck, c.expected, "logs", c.option)
- }
- return errs
-}
diff --git a/ecs/marshall.go b/ecs/marshall.go
deleted file mode 100644
index 2a70b040..00000000
--- a/ecs/marshall.go
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "encoding/json"
- "fmt"
- "strings"
-
- "github.com/awslabs/goformation/v4/cloudformation"
- "github.com/sanathkr/go-yaml"
-)
-
-func marshall(template *cloudformation.Template, format string) ([]byte, error) {
- var (
- source func() ([]byte, error)
- marshal func(in interface{}) ([]byte, error)
- unmarshal func(in []byte, out interface{}) error
- )
- switch format {
- case "yaml":
- source = template.YAML
- marshal = yaml.Marshal
- unmarshal = yaml.Unmarshal
- case "json":
- source = template.JSON
- marshal = func(in interface{}) ([]byte, error) {
- return json.MarshalIndent(in, "", " ")
- }
- unmarshal = json.Unmarshal
- default:
- return nil, fmt.Errorf("unsupported format %q", format)
- }
-
- raw, err := source()
- if err != nil {
- return nil, err
- }
-
- var unmarshalled interface{}
- if err := unmarshal(raw, &unmarshalled); err != nil {
- return nil, fmt.Errorf("invalid JSON: %s", err)
- }
-
- if input, ok := unmarshalled.(map[interface{}]interface{}); ok {
- if resources, ok := input["Resources"]; ok {
- for _, uresource := range resources.(map[interface{}]interface{}) {
- if resource, ok := uresource.(map[interface{}]interface{}); ok {
- if resource["Type"] == "AWS::ECS::TaskDefinition" {
- properties := resource["Properties"].(map[interface{}]interface{})
- for _, def := range properties["ContainerDefinitions"].([]interface{}) {
- containerDefinition := def.(map[interface{}]interface{})
- if strings.HasSuffix(containerDefinition["Name"].(string), "_InitContainer") {
- containerDefinition["Essential"] = false
- }
- }
- }
- }
- }
- }
- }
-
- return marshal(unmarshalled)
-}
diff --git a/ecs/notimplemented.go b/ecs/notimplemented.go
deleted file mode 100644
index ca2e9f01..00000000
--- a/ecs/notimplemented.go
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
-
- "github.com/compose-spec/compose-go/types"
- "github.com/docker/compose/v2/pkg/api"
-)
-
-func (b *ComposeECS) Build(ctx context.Context, project *types.Project, options api.BuildOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Push(ctx context.Context, project *types.Project, options api.PushOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Pull(ctx context.Context, project *types.Project, options api.PullOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Create(ctx context.Context, project *types.Project, opts api.CreateOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Start(ctx context.Context, project *types.Project, options api.StartOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Restart(ctx context.Context, project *types.Project, options api.RestartOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Stop(ctx context.Context, project *types.Project, options api.StopOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Pause(ctx context.Context, project string, options api.PauseOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) UnPause(ctx context.Context, project string, options api.PauseOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Events(ctx context.Context, project string, options api.EventsOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Port(ctx context.Context, project string, service string, port int, options api.PortOptions) (string, int, error) {
- return "", 0, api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Copy(ctx context.Context, project *types.Project, options api.CopyOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) RunOneOffContainer(ctx context.Context, project *types.Project, opts api.RunOptions) (int, error) {
- return 0, api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Remove(ctx context.Context, project *types.Project, options api.RemoveOptions) error {
- return api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Images(ctx context.Context, projectName string, options api.ImagesOptions) ([]api.ImageSummary, error) {
- return nil, api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Top(ctx context.Context, projectName string, services []string) ([]api.ContainerProcSummary, error) {
- return nil, api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Exec(ctx context.Context, project string, opts api.RunOptions) (int, error) {
- return 0, api.ErrNotImplemented
-}
-
-func (b *ComposeECS) Kill(ctx context.Context, project *types.Project, options api.KillOptions) error {
- return api.ErrNotImplemented
-}
diff --git a/ecs/ps.go b/ecs/ps.go
deleted file mode 100644
index e553c171..00000000
--- a/ecs/ps.go
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
-
- "github.com/docker/compose/v2/pkg/api"
-
- "github.com/docker/compose-ecs/utils"
-)
-
-func (b *ComposeECS) Ps(ctx context.Context, projectName string, options api.PsOptions) ([]api.ContainerSummary, error) {
- if err := checkUnsupportedPsOptions(ctx, options); err != nil {
- return nil, err
- }
-
- cluster, err := b.aws.GetStackClusterID(ctx, projectName)
- if err != nil {
- return nil, err
- }
- servicesARN, err := b.aws.ListStackServices(ctx, projectName)
- if err != nil {
- return nil, err
- }
-
- if len(servicesARN) == 0 {
- return nil, nil
- }
-
- summary := []api.ContainerSummary{}
- for _, arn := range servicesARN {
- service, err := b.aws.DescribeService(ctx, cluster, arn)
- if err != nil {
- return nil, err
- }
-
- tasks, err := b.aws.DescribeServiceTasks(ctx, cluster, projectName, service.Name)
- if err != nil {
- return nil, err
- }
-
- for i, t := range tasks {
- t.Publishers = service.Publishers
- tasks[i] = t
- }
- summary = append(summary, tasks...)
- }
- return summary, nil
-}
-
-func checkUnsupportedPsOptions(ctx context.Context, o api.PsOptions) error {
- return utils.CheckUnsupported(ctx, nil, o.All, false, "ps", "all")
-}
diff --git a/ecs/resolv/Dockerfile b/ecs/resolv/Dockerfile
deleted file mode 100644
index dddd3aa8..00000000
--- a/ecs/resolv/Dockerfile
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2020 Docker Compose CLI authors
-
-# 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.
-
-FROM golang:1.19 AS builder
-WORKDIR $GOPATH/src/github.com/docker/compose-ecs/ecs/resolv
-COPY . .
-RUN GO111MODULE=auto CGO_ENABLED=0 go build -ldflags="-w -s" -o /go/bin/resolv main/main.go
-
-FROM scratch
-COPY --from=builder /go/bin/resolv /resolv
-ENTRYPOINT ["/resolv"]
diff --git a/ecs/resolv/main/main.go b/ecs/resolv/main/main.go
deleted file mode 100644
index 7835a8cc..00000000
--- a/ecs/resolv/main/main.go
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 main
-
-import (
- "fmt"
- "os"
-
- "github.com/docker/compose-ecs/ecs/resolv"
-)
-
-const resolvconf = "/etc/resolv.conf"
-
-func main() {
- if len(os.Args) < 2 {
- fmt.Fprint(os.Stderr, "usage: resolv DOMAIN [DOMAIN]")
- os.Exit(1)
- }
-
- err := resolv.SetSearchDomains(resolvconf, os.Args[1:]...)
- if err != nil {
- fmt.Fprint(os.Stderr, err.Error())
- os.Exit(1)
- }
-}
diff --git a/ecs/resolv/resolv.go b/ecs/resolv/resolv.go
deleted file mode 100644
index f516405a..00000000
--- a/ecs/resolv/resolv.go
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 resolv
-
-import (
- "os"
- "strings"
-)
-
-// SetSearchDomains appends a `search` directive to resolv.conf file for domains
-func SetSearchDomains(file string, domains ...string) error {
- search := strings.Join(domains, " ")
-
- f, err := os.OpenFile(file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
- if err != nil {
- return err
- }
- defer f.Close() //nolint:errcheck
- _, err = f.WriteString("\nsearch " + search)
- return err
-}
diff --git a/ecs/resolv/resolv_test.go b/ecs/resolv/resolv_test.go
deleted file mode 100644
index c027039f..00000000
--- a/ecs/resolv/resolv_test.go
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 resolv
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- "gotest.tools/v3/assert"
- "gotest.tools/v3/fs"
- "gotest.tools/v3/golden"
-)
-
-func TestSetDomain(t *testing.T) {
- dir := fs.NewDir(t, "resolv").Path()
- f := filepath.Join(dir, "resolv.conf")
- touch(t, f)
-
- err := SetSearchDomains(f, "foo", "bar", "zot")
- assert.NilError(t, err)
-
- got, err := os.ReadFile(f)
- assert.NilError(t, err)
- golden.Assert(t, string(got), "resolv.conf.golden")
-}
-
-func touch(t *testing.T, f string) {
- file, err := os.Create(f)
- assert.NilError(t, err)
- err = file.Close()
- assert.NilError(t, err)
-}
diff --git a/ecs/resolv/testdata/resolv.conf.golden b/ecs/resolv/testdata/resolv.conf.golden
deleted file mode 100644
index ed0e2453..00000000
--- a/ecs/resolv/testdata/resolv.conf.golden
+++ /dev/null
@@ -1,2 +0,0 @@
-
-search foo bar zot
\ No newline at end of file
diff --git a/ecs/sdk.go b/ecs/sdk.go
index 784654b2..80241129 100644
--- a/ecs/sdk.go
+++ b/ecs/sdk.go
@@ -1,350 +1,70 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
import (
"bytes"
"context"
- "encoding/json"
"fmt"
"strings"
"time"
- "github.com/aws/aws-sdk-go/aws"
- "github.com/aws/aws-sdk-go/aws/arn"
- "github.com/aws/aws-sdk-go/aws/request"
- "github.com/aws/aws-sdk-go/aws/session"
- "github.com/aws/aws-sdk-go/service/autoscaling"
- "github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface"
- "github.com/aws/aws-sdk-go/service/cloudformation"
- "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface"
- "github.com/aws/aws-sdk-go/service/cloudwatchlogs"
- "github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface"
- "github.com/aws/aws-sdk-go/service/ec2"
- "github.com/aws/aws-sdk-go/service/ec2/ec2iface"
- "github.com/aws/aws-sdk-go/service/ecs"
- "github.com/aws/aws-sdk-go/service/ecs/ecsiface"
- "github.com/aws/aws-sdk-go/service/efs"
- "github.com/aws/aws-sdk-go/service/efs/efsiface"
- "github.com/aws/aws-sdk-go/service/elbv2"
- "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface"
- "github.com/aws/aws-sdk-go/service/iam"
- "github.com/aws/aws-sdk-go/service/iam/iamiface"
- "github.com/aws/aws-sdk-go/service/s3"
- "github.com/aws/aws-sdk-go/service/s3/s3iface"
- "github.com/aws/aws-sdk-go/service/s3/s3manager"
- "github.com/aws/aws-sdk-go/service/secretsmanager"
- "github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface"
- "github.com/aws/aws-sdk-go/service/ssm"
- "github.com/aws/aws-sdk-go/service/ssm/ssmiface"
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
+ "github.com/aws/aws-sdk-go-v2/service/cloudformation"
+ cloudformationtypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types"
+ "github.com/aws/aws-sdk-go-v2/service/s3"
+ s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/docker/compose/v2/pkg/api"
- "github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-uuid"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-
- "github.com/docker/compose-ecs/internal"
)
type sdk struct {
- ECS ecsiface.ECSAPI
- EC2 ec2iface.EC2API
- EFS efsiface.EFSAPI
- ELB elbv2iface.ELBV2API
- CW cloudwatchlogsiface.CloudWatchLogsAPI
- IAM iamiface.IAMAPI
- CF cloudformationiface.CloudFormationAPI
- SM secretsmanageriface.SecretsManagerAPI
- SSM ssmiface.SSMAPI
- AG autoscalingiface.AutoScalingAPI
- S3 s3iface.S3API
- uploader *s3manager.Uploader
-}
-
-// sdk implement API
-var _ API = sdk{}
-
-// UserAgentName is the ECS specific user agent used by the cli
-const UserAgentName = "Compose ECS"
-
-func NewAPI(sess *session.Session) API {
- return newSDK(sess)
-}
-
-func newSDK(sess *session.Session) sdk {
- sess.Handlers.Build.PushBack(func(r *request.Request) {
- request.AddToUserAgent(r, UserAgentName+"/"+internal.Version)
- })
- return sdk{
- ECS: ecs.New(sess),
- EC2: ec2.New(sess),
- EFS: efs.New(sess),
- ELB: elbv2.New(sess),
- CW: cloudwatchlogs.New(sess),
- IAM: iam.New(sess),
- CF: cloudformation.New(sess),
- SM: secretsmanager.New(sess),
- SSM: ssm.New(sess),
- AG: autoscaling.New(sess),
- S3: s3.New(sess),
- uploader: s3manager.NewUploader(sess),
- }
-}
-
-func (s sdk) CheckRequirements(ctx context.Context, region string) error {
- settings, err := s.ECS.ListAccountSettingsWithContext(ctx, &ecs.ListAccountSettingsInput{
- EffectiveSettings: aws.Bool(true),
- Name: aws.String("serviceLongArnFormat"),
- })
- if err != nil {
- return err
- }
- serviceLongArnFormat := settings.Settings[0].Value
- if *serviceLongArnFormat != "enabled" {
- return fmt.Errorf("this tool requires the \"new ARN resource ID format\".\n"+
- "Check https://%s.console.aws.amazon.com/ecs/home#/settings\n"+
- "Learn more: https://aws.amazon.com/blogs/compute/migrating-your-amazon-ecs-deployment-to-the-new-arn-and-resource-id-format-2", region)
- }
- return nil
-}
-
-func (s sdk) ResolveCluster(ctx context.Context, nameOrArn string) (awsResource, error) {
- logrus.Debug("CheckRequirements if cluster was already created: ", nameOrArn)
- clusters, err := s.ECS.DescribeClustersWithContext(ctx, &ecs.DescribeClustersInput{
- Clusters: []*string{aws.String(nameOrArn)},
- })
- if err != nil {
- return nil, err
- }
- if len(clusters.Clusters) == 0 {
- return nil, errors.Wrapf(api.ErrNotFound, "cluster %q does not exist", nameOrArn)
- }
- it := clusters.Clusters[0]
- return existingAWSResource{
- arn: aws.StringValue(it.ClusterArn),
- id: aws.StringValue(it.ClusterName),
- }, nil
+ cfg aws.Config
+ cloudformation *cloudformation.Client
+ s3 *s3.Client
}
-func (s sdk) CreateCluster(ctx context.Context, name string) (string, error) {
- logrus.Debug("Create cluster ", name)
- response, err := s.ECS.CreateClusterWithContext(ctx, &ecs.CreateClusterInput{ClusterName: aws.String(name)})
- if err != nil {
- return "", err
- }
- return *response.Cluster.Status, nil
-}
-
-func (s sdk) CheckVPC(ctx context.Context, vpcID string) error {
- logrus.Debug("CheckRequirements on VPC : ", vpcID)
- output, err := s.EC2.DescribeVpcAttributeWithContext(ctx, &ec2.DescribeVpcAttributeInput{
- VpcId: aws.String(vpcID),
- Attribute: aws.String("enableDnsSupport"),
- })
- if err != nil {
- return err
- }
- if !*output.EnableDnsSupport.Value {
- return fmt.Errorf("VPC %q doesn't have DNS resolution enabled", vpcID)
- }
- return nil
-}
-
-func (s sdk) GetDefaultVPC(ctx context.Context) (string, error) {
- logrus.Debug("Retrieve default VPC")
- vpcs, err := s.EC2.DescribeVpcsWithContext(ctx, &ec2.DescribeVpcsInput{
- Filters: []*ec2.Filter{
- {
- Name: aws.String("isDefault"),
- Values: []*string{aws.String("true")},
- },
- },
- })
- if err != nil {
- return "", err
- }
- if len(vpcs.Vpcs) == 0 {
- return "", fmt.Errorf("account has no default VPC. Set VPC to deploy to using 'x-aws-vpc'")
- }
- return *vpcs.Vpcs[0].VpcId, nil
-}
+func (s sdk) CreateChangeSet(ctx context.Context, name string, region string, template []byte) (string, error) {
+ update := fmt.Sprintf("Update%s", time.Now().Format("2006-01-02-15-04-05"))
-func (s sdk) GetSubNets(ctx context.Context, vpcID string) ([]awsResource, error) {
- logrus.Debug("Retrieve SubNets")
- var ids []awsResource
- var token *string
- for {
- subnets, err := s.EC2.DescribeSubnetsWithContext(ctx, &ec2.DescribeSubnetsInput{
- Filters: []*ec2.Filter{
- {
- Name: aws.String("vpc-id"),
- Values: []*string{aws.String(vpcID)},
- },
- },
- NextToken: token,
+ changeset, err := s.withTemplate(ctx, name, template, region, func(body *string, url *string) (string, error) {
+ changeset, err := s.cloudformation.CreateChangeSet(ctx, &cloudformation.CreateChangeSetInput{
+ ChangeSetName: aws.String(update),
+ ChangeSetType: cloudformationtypes.ChangeSetTypeUpdate,
+ StackName: aws.String(name),
+ TemplateBody: body,
+ TemplateURL: url,
+ Capabilities: []cloudformationtypes.Capability{cloudformationtypes.CapabilityCapabilityIam},
})
if err != nil {
- return nil, err
- }
- for _, subnet := range subnets.Subnets {
- ids = append(ids, existingAWSResource{
- arn: aws.StringValue(subnet.SubnetArn),
- id: aws.StringValue(subnet.SubnetId),
- })
- }
-
- if subnets.NextToken == token {
- break
- }
- token = subnets.NextToken
- }
- return ids, nil
-}
-
-func (s sdk) IsPublicSubnet(ctx context.Context, subNetID string) (bool, error) {
- tables, err := s.EC2.DescribeRouteTablesWithContext(ctx, &ec2.DescribeRouteTablesInput{
- Filters: []*ec2.Filter{
- {
- Name: aws.String("association.subnet-id"),
- Values: []*string{aws.String(subNetID)},
- },
- },
- })
- if err != nil {
- return false, err
- }
- if len(tables.RouteTables) == 0 {
- // If a subnet is not explicitly associated with any route table, it is implicitly associated with the main route table.
- // https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-route-tables.html
- return true, nil
- }
- for _, routeTable := range tables.RouteTables {
- for _, route := range routeTable.Routes {
- if aws.StringValue(route.State) != "active" {
- continue
- }
- if strings.HasPrefix(aws.StringValue(route.GatewayId), "igw-") {
- // Connected to an internet Gateway
- return true, nil
- }
- }
- }
- return false, nil
-}
-
-func (s sdk) GetRoleArn(ctx context.Context, name string) (string, error) {
- role, err := s.IAM.GetRoleWithContext(ctx, &iam.GetRoleInput{
- RoleName: aws.String(name),
- })
- if err != nil {
- return "", err
- }
- return *role.Role.Arn, nil
-}
-
-func (s sdk) StackExists(ctx context.Context, name string) (bool, error) {
- stacks, err := s.CF.DescribeStacksWithContext(ctx, &cloudformation.DescribeStacksInput{
- StackName: aws.String(name),
- })
- if err != nil {
- if strings.HasPrefix(err.Error(), fmt.Sprintf("ValidationError: Stack with ID %s does not exist", name)) {
- return false, nil
- }
- return false, nil
- }
- return len(stacks.Stacks) > 0, nil
-}
-
-type uploadedTemplateFunc func(body *string, url *string) (string, error)
-
-const cloudformationBytesLimit = 51200
-
-func (s sdk) withTemplate(ctx context.Context, name string, template []byte, region string, fn uploadedTemplateFunc) (string, error) {
- if len(template) < cloudformationBytesLimit {
- return fn(aws.String(string(template)), nil)
- }
-
- key, err := uuid.GenerateUUID()
- if err != nil {
- return "", err
- }
- bucket := "com.docker.compose." + key
- logrus.Debugf("Create s3 bucket %q to store cloudformation template", bucket)
-
- var configuration *s3.CreateBucketConfiguration
- if region != "us-east-1" {
- configuration = &s3.CreateBucketConfiguration{
- LocationConstraint: aws.String(region),
+ return "", err
}
- }
- _, err = s.S3.CreateBucket(&s3.CreateBucketInput{
- Bucket: aws.String(bucket),
- CreateBucketConfiguration: configuration,
+ return *changeset.Id, err
})
if err != nil {
return "", err
}
- upload, err := s.uploader.UploadWithContext(ctx, &s3manager.UploadInput{
- Key: aws.String("template.yaml"),
- Body: bytes.NewReader(template),
- Bucket: aws.String(bucket),
- ContentType: aws.String("application/x-yaml"),
- Tagging: aws.String(name),
+ desc, err := s.cloudformation.DescribeChangeSet(ctx, &cloudformation.DescribeChangeSetInput{
+ ChangeSetName: aws.String(update),
+ StackName: aws.String(name),
})
-
- if err != nil {
- return "", err
+ if desc.Status == cloudformationtypes.ChangeSetStatusDeleteFailed {
+ return changeset, fmt.Errorf(*desc.StatusReason)
}
- defer func() {
- _, err := s.S3.DeleteObjectWithContext(ctx, &s3.DeleteObjectInput{
- Bucket: aws.String(bucket),
- Key: aws.String("template.yaml"),
- VersionId: upload.VersionID,
- })
- if err != nil {
- logrus.Warnf("Failed to remove S3 bucket: %s", err)
- }
- _, err = s.S3.DeleteBucketWithContext(ctx, &s3.DeleteBucketInput{
- Bucket: aws.String(bucket),
- })
- if err != nil {
- logrus.Warnf("Failed to remove S3 bucket: %s", err)
- }
- }()
-
- return fn(nil, aws.String(upload.Location))
+ return changeset, err
}
func (s sdk) CreateStack(ctx context.Context, name string, region string, template []byte) error {
- logrus.Debug("Create CloudFormation stack")
-
- stackID, err := s.withTemplate(ctx, name, template, region, func(body *string, url *string) (string, error) {
- stack, err := s.CF.CreateStackWithContext(ctx, &cloudformation.CreateStackInput{
- OnFailure: aws.String("DELETE"),
+ _, err := s.withTemplate(ctx, name, template, region, func(body *string, url *string) (string, error) {
+ stack, err := s.cloudformation.CreateStack(ctx, &cloudformation.CreateStackInput{
+ OnFailure: cloudformationtypes.OnFailureDelete,
StackName: aws.String(name),
TemplateBody: body,
TemplateURL: url,
TimeoutInMinutes: nil,
- Capabilities: []*string{
- aws.String(cloudformation.CapabilityCapabilityIam),
- },
- Tags: []*cloudformation.Tag{
+ Capabilities: []cloudformationtypes.Capability{cloudformationtypes.CapabilityCapabilityIam},
+ Tags: []cloudformationtypes.Tag{
{
Key: aws.String(api.ProjectLabel),
Value: aws.String(name),
@@ -354,826 +74,91 @@ func (s sdk) CreateStack(ctx context.Context, name string, region string, templa
if err != nil {
return "", err
}
- return aws.StringValue(stack.StackId), nil
+ return *stack.StackId, nil
})
- logrus.Debugf("Stack %s created", stackID)
return err
}
-func (s sdk) CreateChangeSet(ctx context.Context, name string, region string, template []byte) (string, error) {
- logrus.Debug("Create CloudFormation Changeset")
- update := fmt.Sprintf("Update%s", time.Now().Format("2006-01-02-15-04-05"))
-
- changeset, err := s.withTemplate(ctx, name, template, region, func(body *string, url *string) (string, error) {
- changeset, err := s.CF.CreateChangeSetWithContext(ctx, &cloudformation.CreateChangeSetInput{
- ChangeSetName: aws.String(update),
- ChangeSetType: aws.String(cloudformation.ChangeSetTypeUpdate),
- StackName: aws.String(name),
- TemplateBody: body,
- TemplateURL: url,
- Capabilities: []*string{
- aws.String(cloudformation.CapabilityCapabilityIam),
- },
- })
- if err != nil {
- return "", err
- }
- return aws.StringValue(changeset.Id), err
+func (s sdk) StackExists(ctx context.Context, name string) (bool, error) {
+ stacks, err := s.cloudformation.DescribeStacks(ctx, &cloudformation.DescribeStacksInput{
+ StackName: aws.String(name),
})
if err != nil {
- return "", err
- }
-
- // we have to WaitUntilChangeSetCreateComplete even this in fail with error `ResourceNotReady`
- // so that we can invoke DescribeChangeSet to check status, and then we can know about the actual creation failure cause.
- s.CF.WaitUntilChangeSetCreateCompleteWithContext(ctx, &cloudformation.DescribeChangeSetInput{ // nolint:errcheck
- ChangeSetName: aws.String(changeset),
- })
-
- desc, err := s.CF.DescribeChangeSetWithContext(ctx, &cloudformation.DescribeChangeSetInput{
- ChangeSetName: aws.String(update),
- StackName: aws.String(name),
- })
- if aws.StringValue(desc.Status) == "FAILED" {
- return changeset, fmt.Errorf(aws.StringValue(desc.StatusReason))
+ if strings.HasPrefix(err.Error(), fmt.Sprintf("ValidationError: Stack with ID %s does not exist", name)) {
+ return false, nil
+ }
+ return false, nil
}
-
- return changeset, err
+ return len(stacks.Stacks) > 0, nil
}
func (s sdk) UpdateStack(ctx context.Context, changeset string) error {
- desc, err := s.CF.DescribeChangeSetWithContext(ctx, &cloudformation.DescribeChangeSetInput{
+ desc, err := s.cloudformation.DescribeChangeSet(ctx, &cloudformation.DescribeChangeSetInput{
ChangeSetName: aws.String(changeset),
})
if err != nil {
return err
}
- if strings.HasPrefix(aws.StringValue(desc.StatusReason), "The submitted information didn't contain changes.") {
+ if strings.HasPrefix(*desc.StatusReason, "The submitted information didn't contain changes.") {
return nil
}
- _, err = s.CF.ExecuteChangeSet(&cloudformation.ExecuteChangeSetInput{
+ _, err = s.cloudformation.ExecuteChangeSet(ctx, &cloudformation.ExecuteChangeSetInput{
ChangeSetName: aws.String(changeset),
})
return err
}
-const (
- stackCreate = iota
- stackUpdate
- stackDelete
-)
-
-func (s sdk) WaitStackComplete(ctx context.Context, name string, operation int) error {
- input := &cloudformation.DescribeStacksInput{
- StackName: aws.String(name),
- }
- switch operation {
- case stackCreate:
- return s.CF.WaitUntilStackCreateCompleteWithContext(ctx, input)
- case stackDelete:
- return s.CF.WaitUntilStackDeleteCompleteWithContext(ctx, input)
- default:
- return fmt.Errorf("internal error: unexpected stack operation %d", operation)
- }
-}
-
-func (s sdk) GetStackID(ctx context.Context, name string) (string, error) {
- stacks, err := s.CF.DescribeStacksWithContext(ctx, &cloudformation.DescribeStacksInput{
- StackName: aws.String(name),
- })
- if err != nil {
- return "", err
- }
- return *stacks.Stacks[0].StackId, nil
-}
-
-func (s sdk) ListStacks(ctx context.Context) ([]api.Stack, error) {
- params := cloudformation.DescribeStacksInput{}
- var token *string
- var stacks []api.Stack
- for {
- response, err := s.CF.DescribeStacksWithContext(ctx, ¶ms)
- if err != nil {
- return nil, err
- }
- for _, stack := range response.Stacks {
- for _, t := range stack.Tags {
- if *t.Key == api.ProjectLabel {
- status := api.RUNNING
- switch aws.StringValue(stack.StackStatus) {
- case "CREATE_IN_PROGRESS":
- status = api.STARTING
- case "DELETE_IN_PROGRESS":
- status = api.REMOVING
- case "UPDATE_IN_PROGRESS":
- status = api.UPDATING
- default:
- }
- stacks = append(stacks, api.Stack{
- ID: aws.StringValue(stack.StackId),
- Name: aws.StringValue(stack.StackName),
- Status: status,
- })
- break
- }
- }
- }
- if token == response.NextToken {
- return stacks, nil
- }
- token = response.NextToken
- }
-}
-
-func (s sdk) GetStackClusterID(ctx context.Context, stack string) (string, error) {
- // Note: could use DescribeStackResource but we only can detect `does not exist` case by matching string error message
- var token *string
- for {
- response, err := s.CF.ListStackResourcesWithContext(ctx, &cloudformation.ListStackResourcesInput{
- StackName: aws.String(stack),
- })
- if err != nil {
- return "", err
- }
- for _, r := range response.StackResourceSummaries {
- if aws.StringValue(r.ResourceType) == "AWS::ECS::Cluster" {
- return aws.StringValue(r.PhysicalResourceId), nil
- }
- }
- if token == response.NextToken {
- break
- }
- token = response.NextToken
- }
- // stack is using user-provided cluster
- return s.GetStackMetadataClusterID(ctx, stack)
-}
-
-func (s sdk) GetStackMetadataClusterID(ctx context.Context, stack string) (string, error) {
- res, err := s.CF.GetTemplateSummaryWithContext(ctx, &cloudformation.GetTemplateSummaryInput{
- StackName: aws.String(stack),
- })
- if err != nil {
- return "", err
- }
- c := aws.StringValue(res.Metadata)
- var m templateMetadata
- err = json.Unmarshal([]byte(c), &m)
- if err != nil {
- return "", err
- }
- if m.Cluster == "" {
- return "", errors.Wrap(api.ErrNotFound, "CloudFormation is missing cluster metadata")
- }
-
- return m.Cluster, nil
-}
-
-type templateMetadata struct {
- Cluster string `json:",omitempty"`
-}
-
-func (s sdk) GetServiceTaskDefinition(ctx context.Context, cluster string, serviceArns []string) (map[string]string, error) {
- defs := map[string]string{}
-
- svc := []*string{}
- for _, s := range serviceArns {
- svc = append(svc, aws.String(s))
- }
- for i := 0; i < len(svc); i += 10 {
- end := i + 10
- if end > len(svc) {
- end = len(svc)
- }
- chunk := svc[i:end]
- services, err := s.ECS.DescribeServicesWithContext(ctx, &ecs.DescribeServicesInput{
- Cluster: aws.String(cluster),
- Services: chunk,
- })
- if err != nil {
- return nil, err
- }
- for _, s := range services.Services {
- defs[aws.StringValue(s.ServiceArn)] = aws.StringValue(s.TaskDefinition)
- }
- }
- return defs, nil
-}
-
-func (s sdk) ListStackServices(ctx context.Context, stack string) ([]string, error) {
- arns := []string{}
- var nextToken *string
- for {
- response, err := s.CF.ListStackResourcesWithContext(ctx, &cloudformation.ListStackResourcesInput{
- StackName: aws.String(stack),
- NextToken: nextToken,
- })
- if err != nil {
- return nil, err
- }
- for _, r := range response.StackResourceSummaries {
- if aws.StringValue(r.ResourceType) == "AWS::ECS::Service" {
- if r.PhysicalResourceId != nil {
- arns = append(arns, aws.StringValue(r.PhysicalResourceId))
- }
- }
- }
- nextToken = response.NextToken
- if nextToken == nil {
- break
- }
- }
- return arns, nil
-}
+func (s sdk) withTemplate(ctx context.Context, name string, template []byte, region string, uploadedTemplateFunc func(body *string, url *string) (string, error)) (string, error) {
+ const cloudformationBytesLimit = 51200
-func (s sdk) GetServiceTasks(ctx context.Context, cluster string, service string, stopped bool) ([]*ecs.Task, error) {
- state := "RUNNING"
- if stopped {
- state = "STOPPED"
- }
- var token *string
- var tasks []*ecs.Task
- for {
- response, err := s.ECS.ListTasksWithContext(ctx, &ecs.ListTasksInput{
- Cluster: aws.String(cluster),
- ServiceName: aws.String(service),
- DesiredStatus: aws.String(state),
- })
- if err != nil {
- return nil, err
- }
- if len(response.TaskArns) > 0 {
- taskDescriptions, err := s.ECS.DescribeTasksWithContext(ctx, &ecs.DescribeTasksInput{
- Cluster: aws.String(cluster),
- Tasks: response.TaskArns,
- })
- if err != nil {
- return nil, err
- }
- tasks = append(tasks, taskDescriptions.Tasks...)
- }
- if token == response.NextToken {
- return tasks, nil
- }
- token = response.NextToken
+ if len(template) < cloudformationBytesLimit {
+ return uploadedTemplateFunc(aws.String(string(template)), nil)
}
-}
-func (s sdk) GetTaskStoppedReason(ctx context.Context, cluster string, taskArn string) (string, error) {
- taskDescriptions, err := s.ECS.DescribeTasksWithContext(ctx, &ecs.DescribeTasksInput{
- Cluster: aws.String(cluster),
- Tasks: []*string{aws.String(taskArn)},
- })
+ key, err := uuid.GenerateUUID()
if err != nil {
return "", err
}
- if len(taskDescriptions.Tasks) == 0 {
- return "", nil
- }
- task := taskDescriptions.Tasks[0]
- return fmt.Sprintf(
- "%s: %s",
- aws.StringValue(task.StopCode),
- aws.StringValue(task.StoppedReason)), nil
-
-}
-
-func (s sdk) DescribeStackEvents(ctx context.Context, stackID string) ([]*cloudformation.StackEvent, error) {
- // Fixme implement Paginator on Events and return as a chan(events)
- events := []*cloudformation.StackEvent{}
- var nextToken *string
- for {
- resp, err := s.CF.DescribeStackEventsWithContext(ctx, &cloudformation.DescribeStackEventsInput{
- StackName: aws.String(stackID),
- NextToken: nextToken,
- })
- if err != nil {
- return nil, err
- }
-
- events = append(events, resp.StackEvents...)
- if resp.NextToken == nil {
- return events, nil
- }
- nextToken = resp.NextToken
- }
-}
-
-func (s sdk) ListStackParameters(ctx context.Context, name string) (map[string]string, error) {
- st, err := s.CF.DescribeStacksWithContext(ctx, &cloudformation.DescribeStacksInput{
- NextToken: nil,
- StackName: aws.String(name),
- })
- if err != nil {
- return nil, err
- }
- parameters := map[string]string{}
- for _, parameter := range st.Stacks[0].Parameters {
- parameters[aws.StringValue(parameter.ParameterKey)] = aws.StringValue(parameter.ParameterValue)
- }
- return parameters, nil
-}
-
-type stackResource struct {
- LogicalID string
- Type string
- ARN string
- Status string
-}
-
-type stackResourceFn func(r stackResource) error
-
-type stackResources []stackResource
-
-func (resources stackResources) apply(awsType string, fn stackResourceFn) error {
- var errs *multierror.Error
- for _, r := range resources {
- if r.Type == awsType {
- err := fn(r)
- if err != nil {
- errs = multierror.Append(err)
- }
- }
- }
- return errs.ErrorOrNil()
-}
-
-func (s sdk) ListStackResources(ctx context.Context, name string) (stackResources, error) {
- var token *string
- var resources stackResources
- for {
- response, err := s.CF.ListStackResourcesWithContext(ctx, &cloudformation.ListStackResourcesInput{
- StackName: aws.String(name),
- })
- if err != nil {
- return nil, err
- }
-
- for _, r := range response.StackResourceSummaries {
- resources = append(resources, stackResource{
- LogicalID: aws.StringValue(r.LogicalResourceId),
- Type: aws.StringValue(r.ResourceType),
- ARN: aws.StringValue(r.PhysicalResourceId),
- Status: aws.StringValue(r.ResourceStatus),
- })
- }
- if token == response.NextToken {
- return resources, nil
- }
- token = response.NextToken
- }
-}
-
-func (s sdk) DeleteStack(ctx context.Context, name string) error {
- logrus.Debug("Delete CloudFormation stack")
- _, err := s.CF.DeleteStackWithContext(ctx, &cloudformation.DeleteStackInput{
- StackName: aws.String(name),
- })
- return err
-}
-
-func (s sdk) GetLogs(ctx context.Context, name string, consumer func(container string, service string, message string), follow bool) error {
- logGroup := fmt.Sprintf("/docker-compose/%s", name)
- var startTime int64
- for {
- select {
- case <-ctx.Done():
- return nil
- default:
- var hasMore = true
- var token *string
- for hasMore {
- events, err := s.CW.FilterLogEvents(&cloudwatchlogs.FilterLogEventsInput{
- LogGroupName: aws.String(logGroup),
- NextToken: token,
- StartTime: aws.Int64(startTime),
- })
- if err != nil {
- return err
- }
- if events.NextToken == nil {
- hasMore = false
- } else {
- token = events.NextToken
- }
-
- for _, event := range events.Events {
- p := strings.Split(aws.StringValue(event.LogStreamName), "/")
- consumer(p[1], p[2], aws.StringValue(event.Message))
- startTime = *event.IngestionTime
- }
- }
- }
- if !follow {
- return nil
- }
- time.Sleep(500 * time.Millisecond)
- }
-}
-
-func (s sdk) DescribeService(ctx context.Context, cluster string, arn string) (api.ServiceStatus, error) {
- services, err := s.ECS.DescribeServicesWithContext(ctx, &ecs.DescribeServicesInput{
- Cluster: aws.String(cluster),
- Services: []*string{aws.String(arn)},
- Include: aws.StringSlice([]string{"TAGS"}),
- })
- if err != nil {
- return api.ServiceStatus{}, err
- }
-
- for _, f := range services.Failures {
- return api.ServiceStatus{}, errors.Wrapf(api.ErrNotFound, "can't get service status %s: %s", aws.StringValue(f.Detail), aws.StringValue(f.Reason))
- }
- service := services.Services[0]
- var name string
- for _, t := range service.Tags {
- if *t.Key == api.ServiceLabel {
- name = aws.StringValue(t.Value)
- }
- }
- if name == "" {
- return api.ServiceStatus{}, fmt.Errorf("service %s doesn't have a %s tag", *service.ServiceArn, api.ServiceLabel)
- }
- targetGroupArns := []string{}
- for _, lb := range service.LoadBalancers {
- targetGroupArns = append(targetGroupArns, *lb.TargetGroupArn)
- }
- // getURLwithPortMapping makes 2 queries
- // one to get the target groups and another for load balancers
- loadBalancers, err := s.getURLWithPortMapping(ctx, targetGroupArns)
- if err != nil {
- return api.ServiceStatus{}, err
- }
- return api.ServiceStatus{
- ID: aws.StringValue(service.ServiceName),
- Name: name,
- Replicas: int(aws.Int64Value(service.RunningCount)),
- Desired: int(aws.Int64Value(service.DesiredCount)),
- Publishers: loadBalancers,
- }, nil
-}
-
-func (s sdk) DescribeServiceTasks(ctx context.Context, cluster string, project string, service string) ([]api.ContainerSummary, error) {
- var summary []api.ContainerSummary
- familly := fmt.Sprintf("%s-%s", project, service)
- var token *string
- for {
- list, err := s.ECS.ListTasks(&ecs.ListTasksInput{
- Cluster: aws.String(cluster),
- Family: aws.String(familly),
- LaunchType: nil,
- MaxResults: nil,
- NextToken: token,
- })
- if err != nil {
- return nil, err
- }
-
- if len(list.TaskArns) == 0 {
- break
- }
- tasks, err := s.ECS.DescribeTasksWithContext(ctx, &ecs.DescribeTasksInput{
- Cluster: aws.String(cluster),
- Include: aws.StringSlice([]string{"TAGS"}),
- Tasks: list.TaskArns,
- })
- if err != nil {
- return nil, err
- }
-
- for _, t := range tasks.Tasks {
- var project string
- var service string
- for _, tag := range t.Tags {
- switch aws.StringValue(tag.Key) {
- case api.ProjectLabel:
- project = aws.StringValue(tag.Value)
- case api.ServiceLabel:
- service = aws.StringValue(tag.Value)
- }
- }
-
- id, err := arn.Parse(aws.StringValue(t.TaskArn))
- if err != nil {
- return nil, err
- }
-
- summary = append(summary, api.ContainerSummary{
- ID: id.String(),
- Name: id.Resource,
- Project: project,
- Service: service,
- //nolint:staticcheck // Preserving for compatibility
- State: strings.Title(strings.ToLower(aws.StringValue(t.LastStatus))),
- })
- }
-
- if list.NextToken == token {
- break
- }
- token = list.NextToken
- }
-
- return summary, nil
-}
-
-func (s sdk) getURLWithPortMapping(ctx context.Context, targetGroupArns []string) ([]api.PortPublisher, error) {
- if len(targetGroupArns) == 0 {
- return nil, nil
- }
- groups, err := s.ELB.DescribeTargetGroups(&elbv2.DescribeTargetGroupsInput{
- TargetGroupArns: aws.StringSlice(targetGroupArns),
- })
- if err != nil {
- return nil, err
- }
- lbarns := []*string{}
- for _, tg := range groups.TargetGroups {
- lbarns = append(lbarns, tg.LoadBalancerArns...)
- }
-
- lbs, err := s.ELB.DescribeLoadBalancersWithContext(ctx, &elbv2.DescribeLoadBalancersInput{
- LoadBalancerArns: lbarns,
- })
-
- if err != nil {
- return nil, err
- }
- filterLB := func(arn *string, lbs []*elbv2.LoadBalancer) *elbv2.LoadBalancer {
- if aws.StringValue(arn) == "" {
- // load balancer arn is nil/""
- return nil
- }
- for _, lb := range lbs {
- if aws.StringValue(lb.LoadBalancerArn) == aws.StringValue(arn) {
- return lb
- }
- }
- return nil
- }
- loadBalancers := []api.PortPublisher{}
- for _, tg := range groups.TargetGroups {
- for _, lbarn := range tg.LoadBalancerArns {
- lb := filterLB(lbarn, lbs.LoadBalancers)
- if lb == nil {
- continue
- }
- loadBalancers = append(loadBalancers, api.PortPublisher{
- URL: fmt.Sprintf("%s:%d", aws.StringValue(lb.DNSName), aws.Int64Value(tg.Port)),
- TargetPort: int(aws.Int64Value(tg.Port)),
- PublishedPort: int(aws.Int64Value(tg.Port)),
- Protocol: strings.ToLower(aws.StringValue(tg.Protocol)),
- })
-
- }
- }
- return loadBalancers, nil
-}
-
-func (s sdk) ListTasks(ctx context.Context, cluster string, family string) ([]string, error) {
- var token *string
- var arns []string
- for {
- response, err := s.ECS.ListTasksWithContext(ctx, &ecs.ListTasksInput{
- Cluster: aws.String(cluster),
- Family: aws.String(family),
- })
- if err != nil {
- return nil, err
- }
- for _, arn := range response.TaskArns {
- arns = append(arns, *arn)
- }
- if token == response.NextToken {
- return arns, nil
- }
- token = response.NextToken
- }
-}
+ bucket := "com.docker.compose." + key
-func (s sdk) GetPublicIPs(ctx context.Context, interfaces ...string) (map[string]string, error) {
- var token *string
- publicIPs := map[string]string{}
- for {
- response, err := s.EC2.DescribeNetworkInterfaces(&ec2.DescribeNetworkInterfacesInput{
- NetworkInterfaceIds: aws.StringSlice(interfaces),
- })
- if err != nil {
- return nil, err
- }
- for _, interf := range response.NetworkInterfaces {
- if interf.Association != nil {
- publicIPs[aws.StringValue(interf.NetworkInterfaceId)] = aws.StringValue(interf.Association.PublicIp)
- }
- }
- if token == response.NextToken {
- return publicIPs, nil
+ var configuration *s3types.CreateBucketConfiguration
+ if region != "us-east-1" {
+ configuration = &s3types.CreateBucketConfiguration{
+ LocationConstraint: s3types.BucketLocationConstraint(region),
}
- token = response.NextToken
- }
-}
-
-func (s sdk) ResolveLoadBalancer(ctx context.Context, nameOrArn string) (awsResource, string, string, []awsResource, error) {
- logrus.Debug("Check if LoadBalancer exists: ", nameOrArn)
- var arns []*string
- var names []*string
- if arn.IsARN(nameOrArn) {
- arns = append(arns, aws.String(nameOrArn))
- } else {
- names = append(names, aws.String(nameOrArn))
- }
-
- lbs, err := s.ELB.DescribeLoadBalancersWithContext(ctx, &elbv2.DescribeLoadBalancersInput{
- LoadBalancerArns: arns,
- Names: names,
- })
- if err != nil {
- return nil, "", "", nil, err
- }
- if len(lbs.LoadBalancers) == 0 {
- return nil, "", "", nil, errors.Wrapf(api.ErrNotFound, "load balancer %q does not exist", nameOrArn)
- }
- it := lbs.LoadBalancers[0]
- var subNets []awsResource
- for _, az := range it.AvailabilityZones {
- subNets = append(subNets, existingAWSResource{
- id: aws.StringValue(az.SubnetId),
- })
}
- return existingAWSResource{
- arn: aws.StringValue(it.LoadBalancerArn),
- id: aws.StringValue(it.LoadBalancerName),
- }, aws.StringValue(it.Type), aws.StringValue(it.VpcId), subNets, nil
-}
-
-func (s sdk) GetLoadBalancerURL(ctx context.Context, arn string) (string, error) {
- logrus.Debug("Retrieve load balancer URL: ", arn)
- lbs, err := s.ELB.DescribeLoadBalancersWithContext(ctx, &elbv2.DescribeLoadBalancersInput{
- LoadBalancerArns: []*string{aws.String(arn)},
+ _, err = s.s3.CreateBucket(ctx, &s3.CreateBucketInput{
+ Bucket: aws.String(bucket),
+ CreateBucketConfiguration: configuration,
})
if err != nil {
return "", err
}
- dnsName := aws.StringValue(lbs.LoadBalancers[0].DNSName)
- if dnsName == "" {
- return "", fmt.Errorf("Load balancer %s doesn't have a dns name", aws.StringValue(lbs.LoadBalancers[0].LoadBalancerArn))
- }
- return dnsName, nil
-}
-func (s sdk) GetParameter(ctx context.Context, name string) (string, error) {
- parameter, err := s.SSM.GetParameterWithContext(ctx, &ssm.GetParameterInput{
- Name: aws.String(name),
+ upload, err := manager.NewUploader(s.s3).Upload(ctx, &s3.PutObjectInput{
+ Key: aws.String("template.yaml"),
+ Body: bytes.NewReader(template),
+ Bucket: aws.String(bucket),
+ ContentType: aws.String("application/x-yaml"),
+ Tagging: aws.String(name),
})
- if err != nil {
- return "", err
- }
- value := *parameter.Parameter.Value
- var ami struct {
- SchemaVersion int `json:"schema_version"`
- ImageName string `json:"image_name"`
- ImageID string `json:"image_id"`
- OS string `json:"os"`
- ECSRuntimeVersion string `json:"ecs_runtime_verion"`
- ECSAgentVersion string `json:"ecs_agent_version"`
- }
- err = json.Unmarshal([]byte(value), &ami)
if err != nil {
return "", err
}
- return ami.ImageID, nil
-}
-
-func (s sdk) SecurityGroupExists(ctx context.Context, sg string) (bool, error) {
- desc, err := s.EC2.DescribeSecurityGroupsWithContext(ctx, &ec2.DescribeSecurityGroupsInput{
- GroupIds: aws.StringSlice([]string{sg}),
- })
- if err != nil {
- return false, err
- }
- return len(desc.SecurityGroups) > 0, nil
-}
-
-func (s sdk) DeleteCapacityProvider(ctx context.Context, arn string) error {
- _, err := s.ECS.DeleteCapacityProvider(&ecs.DeleteCapacityProviderInput{
- CapacityProvider: aws.String(arn),
- })
- return err
-}
-
-func (s sdk) DeleteAutoscalingGroup(ctx context.Context, arn string) error {
- _, err := s.AG.DeleteAutoScalingGroup(&autoscaling.DeleteAutoScalingGroupInput{
- AutoScalingGroupName: aws.String(arn),
- ForceDelete: aws.Bool(true),
- })
- return err
-}
-
-func (s sdk) ResolveFileSystem(ctx context.Context, id string) (awsResource, error) {
- desc, err := s.EFS.DescribeFileSystemsWithContext(ctx, &efs.DescribeFileSystemsInput{
- FileSystemId: aws.String(id),
- })
- if err != nil {
- return nil, err
- }
- if len(desc.FileSystems) == 0 {
- return nil, errors.Wrapf(api.ErrNotFound, "EFS file system %q doesn't exist", id)
- }
- it := desc.FileSystems[0]
- return existingAWSResource{
- arn: aws.StringValue(it.FileSystemArn),
- id: aws.StringValue(it.FileSystemId),
- }, nil
-}
-
-func (s sdk) ListFileSystems(ctx context.Context, tags map[string]string) ([]awsResource, error) {
- var results []awsResource
- var token *string
- for {
- desc, err := s.EFS.DescribeFileSystemsWithContext(ctx, &efs.DescribeFileSystemsInput{
- Marker: token,
+ defer func() {
+ _, _ = s.s3.DeleteObject(ctx, &s3.DeleteObjectInput{
+ Bucket: aws.String(bucket),
+ Key: aws.String("template.yaml"),
+ VersionId: upload.VersionID,
})
- if err != nil {
- return nil, err
- }
- for _, filesystem := range desc.FileSystems {
- if containsAll(filesystem.Tags, tags) {
- results = append(results, existingAWSResource{
- arn: aws.StringValue(filesystem.FileSystemArn),
- id: aws.StringValue(filesystem.FileSystemId),
- })
- }
- }
- if desc.NextMarker == token {
- return results, nil
- }
- token = desc.NextMarker
- }
-}
-
-func containsAll(tags []*efs.Tag, required map[string]string) bool {
-TAGS:
- for key, value := range required {
- for _, t := range tags {
- if aws.StringValue(t.Key) == key && aws.StringValue(t.Value) == value {
- continue TAGS
- }
- }
- return false
- }
- return true
-}
-
-func (s sdk) CreateFileSystem(ctx context.Context, tags map[string]string, options VolumeCreateOptions) (awsResource, error) {
- var efsTags []*efs.Tag
- for k, v := range tags {
- efsTags = append(efsTags, &efs.Tag{
- Key: aws.String(k),
- Value: aws.String(v),
+ _, _ = s.s3.DeleteBucket(ctx, &s3.DeleteBucketInput{
+ Bucket: aws.String(bucket),
})
- }
- var (
- k *string
- p *string
- f *float64
- t *string
- )
- if options.ProvisionedThroughputInMibps > 1 {
- f = aws.Float64(options.ProvisionedThroughputInMibps)
- }
- if options.KmsKeyID != "" {
- k = aws.String(options.KmsKeyID)
- }
- if options.PerformanceMode != "" {
- p = aws.String(options.PerformanceMode)
- }
- if options.ThroughputMode != "" {
- t = aws.String(options.ThroughputMode)
- }
- res, err := s.EFS.CreateFileSystemWithContext(ctx, &efs.CreateFileSystemInput{
- Encrypted: aws.Bool(true),
- KmsKeyId: k,
- PerformanceMode: p,
- ProvisionedThroughputInMibps: f,
- ThroughputMode: t,
- Tags: efsTags,
- })
- if err != nil {
- return nil, err
- }
- return existingAWSResource{
- id: aws.StringValue(res.FileSystemId),
- arn: aws.StringValue(res.FileSystemArn),
- }, nil
-}
+ }()
-func (s sdk) DeleteFileSystem(ctx context.Context, id string) error {
- _, err := s.EFS.DeleteFileSystemWithContext(ctx, &efs.DeleteFileSystemInput{
- FileSystemId: aws.String(id),
- })
- return err
+ return uploadedTemplateFunc(nil, aws.String(upload.Location))
}
diff --git a/ecs/secrets.go b/ecs/secrets.go
deleted file mode 100644
index fde56517..00000000
--- a/ecs/secrets.go
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
-
- "github.com/docker/compose-ecs/api/secrets"
-)
-
-func (b *ComposeECS) CreateSecret(ctx context.Context, secret secrets.Secret) (string, error) {
- return b.aws.CreateSecret(ctx, secret)
-}
-
-func (b *ComposeECS) InspectSecret(ctx context.Context, id string) (secrets.Secret, error) {
- return b.aws.InspectSecret(ctx, id)
-}
-
-func (b *ComposeECS) ListSecrets(ctx context.Context) ([]secrets.Secret, error) {
- return b.aws.ListSecrets(ctx)
-}
-
-func (b *ComposeECS) DeleteSecret(ctx context.Context, id string, recover bool) error {
- return b.aws.DeleteSecret(ctx, id, recover)
-}
diff --git a/ecs/secrets/Dockerfile b/ecs/secrets/Dockerfile
deleted file mode 100644
index a518edf1..00000000
--- a/ecs/secrets/Dockerfile
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2020 Docker Compose CLI authors
-
-# 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.
-
-FROM golang:1.19 AS builder
-WORKDIR $GOPATH/src/github.com/docker/compose-ecs/ecs/secrets
-COPY . .
-RUN GO111MODULE=auto CGO_ENABLED=0 go build -ldflags="-w -s" -o /go/bin/secrets main/main.go
-
-FROM scratch
-COPY --from=builder /go/bin/secrets /secrets
-ENTRYPOINT ["/secrets"]
diff --git a/ecs/secrets/init.go b/ecs/secrets/init.go
deleted file mode 100644
index 21be68b7..00000000
--- a/ecs/secrets/init.go
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 secrets
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
-)
-
-// Secret define sensitive data to be bound as file
-type Secret struct {
- Name string
- Keys []string
-}
-
-// CreateSecretFiles retrieve sensitive data from env and store as plain text a a file in path
-func CreateSecretFiles(secret Secret, path string) error {
- value, ok := os.LookupEnv(secret.Name)
- if !ok {
- return fmt.Errorf("%q variable not set", secret.Name)
- }
-
- secrets := filepath.Join(path, secret.Name)
-
- if len(secret.Keys) == 0 {
- // raw Secret
- fmt.Printf("inject Secret %q info %s\n", secret.Name, secrets)
- return os.WriteFile(secrets, []byte(value), 0444)
- }
-
- var unmarshalled interface{}
- err := json.Unmarshal([]byte(value), &unmarshalled)
- if err != nil {
- return fmt.Errorf("%q Secret is not a valid JSON document: %w", secret.Name, err)
- }
-
- dict, ok := unmarshalled.(map[string]interface{})
- if !ok {
- return fmt.Errorf("%q Secret is not a JSON dictionary: %w", secret.Name, err)
- }
- err = os.MkdirAll(secrets, 0755)
- if err != nil {
- return err
- }
-
- if contains(secret.Keys, "*") {
- var keys []string
- for k := range dict {
- keys = append(keys, k)
- }
- secret.Keys = keys
- }
-
- for _, k := range secret.Keys {
- path := filepath.Join(secrets, k)
- fmt.Printf("inject Secret %q info %s\n", k, path)
-
- v, ok := dict[k]
- if !ok {
- return fmt.Errorf("%q Secret has no %q key", secret.Name, k)
- }
-
- var raw []byte
- if s, ok := v.(string); ok {
- raw = []byte(s)
- } else {
- raw, err = json.Marshal(v)
- if err != nil {
- return err
- }
- }
-
- err = os.WriteFile(path, raw, 0444)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func contains(keys []string, s string) bool {
- for _, k := range keys {
- if k == s {
- return true
- }
- }
- return false
-}
diff --git a/ecs/secrets/init_test.go b/ecs/secrets/init_test.go
deleted file mode 100644
index 369b7515..00000000
--- a/ecs/secrets/init_test.go
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 secrets
-
-import (
- "os"
- "path/filepath"
- "testing"
-
- "gotest.tools/v3/assert"
- "gotest.tools/v3/fs"
-)
-
-func TestRawSecret(t *testing.T) {
- dir := fs.NewDir(t, "secrets").Path()
- err := os.Setenv("raw", "something_secret")
- assert.NilError(t, err)
- defer os.Unsetenv("raw") // nolint:errcheck
-
- err = CreateSecretFiles(Secret{
- Name: "raw",
- Keys: nil,
- }, dir)
- assert.NilError(t, err)
- file, err := os.ReadFile(filepath.Join(dir, "raw"))
- assert.NilError(t, err)
- content := string(file)
- assert.Equal(t, content, "something_secret")
-}
-
-func TestSelectedKeysSecret(t *testing.T) {
- dir := fs.NewDir(t, "secrets").Path()
- err := os.Setenv("json", `
-{
- "foo": "bar",
- "zot": "qix"
-}`)
- assert.NilError(t, err)
- defer os.Unsetenv("json") // nolint:errcheck
-
- err = CreateSecretFiles(Secret{
- Name: "json",
- Keys: []string{"foo"},
- }, dir)
- assert.NilError(t, err)
- file, err := os.ReadFile(filepath.Join(dir, "json", "foo"))
- assert.NilError(t, err)
- content := string(file)
- assert.Equal(t, content, "bar")
-
- _, err = os.Stat(filepath.Join(dir, "json", "zot"))
- assert.Check(t, os.IsNotExist(err))
-}
-
-func TestAllKeysSecret(t *testing.T) {
- dir := fs.NewDir(t, "secrets").Path()
- err := os.Setenv("json", `
-{
- "foo": "bar",
- "zot": "qix"
-}`)
- assert.NilError(t, err)
- defer os.Unsetenv("json") // nolint:errcheck
-
- err = CreateSecretFiles(Secret{
- Name: "json",
- Keys: []string{"*"},
- }, dir)
- assert.NilError(t, err)
- file, err := os.ReadFile(filepath.Join(dir, "json", "foo"))
- assert.NilError(t, err)
- content := string(file)
- assert.Equal(t, content, "bar")
-
- file, err = os.ReadFile(filepath.Join(dir, "json", "zot"))
- assert.NilError(t, err)
- content = string(file)
- assert.Equal(t, content, "qix")
-}
-
-func TestUnknownSecret(t *testing.T) {
- dir := fs.NewDir(t, "secrets").Path()
-
- err := CreateSecretFiles(Secret{
- Name: "not_set",
- Keys: nil,
- }, dir)
- assert.Check(t, err != nil)
-}
diff --git a/ecs/secrets/main/main.go b/ecs/secrets/main/main.go
deleted file mode 100644
index 4135193d..00000000
--- a/ecs/secrets/main/main.go
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 main
-
-import (
- "encoding/json"
- "fmt"
- "os"
-
- "github.com/docker/compose-ecs/ecs/secrets"
-)
-
-const secretsFolder = "/run/secrets"
-
-func main() {
- if len(os.Args) != 2 {
- fmt.Fprint(os.Stderr, "usage: secrets ")
- os.Exit(1)
- }
-
- var input []secrets.Secret
- err := json.Unmarshal([]byte(os.Args[1]), &input)
- if err != nil {
- fmt.Fprint(os.Stderr, err.Error())
- os.Exit(1)
- }
-
- for _, secret := range input {
- err := secrets.CreateSecretFiles(secret, secretsFolder)
- if err != nil {
- fmt.Fprint(os.Stderr, err.Error())
- os.Exit(1)
- }
- }
-}
diff --git a/ecs/service.go b/ecs/service.go
new file mode 100644
index 00000000..cc83a2f0
--- /dev/null
+++ b/ecs/service.go
@@ -0,0 +1,226 @@
+package ecs
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/aws/aws-sdk-go-v2/config"
+ "github.com/aws/aws-sdk-go-v2/service/cloudformation"
+ "github.com/aws/aws-sdk-go-v2/service/s3"
+ "github.com/compose-spec/compose-go/v2/types"
+ "github.com/docker/compose/v2/pkg/api"
+ "sigs.k8s.io/kustomize/kyaml/yaml"
+ "sigs.k8s.io/kustomize/kyaml/yaml/merge2"
+)
+
+type service struct {
+ sdk sdk
+ dryRun bool
+}
+
+var _ api.Service = &service{}
+
+func NewService(ctx context.Context) (api.Service, error) {
+ if cfg, err := config.LoadDefaultConfig(ctx); err != nil {
+ return nil, err
+ } else {
+ return service{
+ sdk: sdk{
+ cfg: cfg,
+ cloudformation: cloudformation.NewFromConfig(cfg),
+ s3: s3.NewFromConfig(cfg),
+ },
+ }, nil
+ }
+}
+
+func (b service) Attach(ctx context.Context, projectName string, options api.AttachOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Build(ctx context.Context, project *types.Project, options api.BuildOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Config(ctx context.Context, project *types.Project, options api.ConfigOptions) ([]byte, error) {
+ if options.Format != "yaml" {
+ return nil, fmt.Errorf("format %q is not supported", options.Format)
+ }
+
+ template, err := convert(project)
+ if err != nil {
+ return nil, err
+ }
+
+ bytes, err := template.YAML()
+ if err != nil {
+ return nil, err
+ }
+
+ x, ok := project.Extensions[extensionCloudFormation]
+ if !ok {
+ return bytes, nil
+ }
+
+ nodes, err := yaml.Parse(string(bytes))
+ if err != nil {
+ return nil, err
+ }
+
+ bytes, err = yaml.Marshal(x)
+ if err != nil {
+ return nil, err
+ }
+
+ overlay, err := yaml.Parse(string(bytes))
+ if err != nil {
+ return nil, err
+ }
+
+ nodes, err = merge2.Merge(overlay, nodes, yaml.MergeOptions{
+ ListIncreaseDirection: yaml.MergeOptionsListPrepend,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ s, err := nodes.String()
+ if err != nil {
+ return nil, err
+ }
+
+ return []byte(s), err
+}
+
+func (b service) Copy(ctx context.Context, projectName string, options api.CopyOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Create(ctx context.Context, project *types.Project, opts api.CreateOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Down(ctx context.Context, projectName string, options api.DownOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) DryRunMode(ctx context.Context, dryRun bool) (context.Context, error) {
+ b.dryRun = dryRun
+ return ctx, nil
+}
+
+func (b service) Events(ctx context.Context, project string, options api.EventsOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Exec(ctx context.Context, project string, opts api.RunOptions) (int, error) {
+ return 0, api.ErrNotImplemented
+}
+
+func (b service) Images(ctx context.Context, projectName string, options api.ImagesOptions) ([]api.ImageSummary, error) {
+ return nil, api.ErrNotImplemented
+}
+
+func (b service) Kill(ctx context.Context, projectName string, options api.KillOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) List(ctx context.Context, options api.ListOptions) ([]api.Stack, error) {
+ return nil, api.ErrNotImplemented
+}
+
+func (b service) Logs(ctx context.Context, projectName string, consumer api.LogConsumer, options api.LogOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) MaxConcurrency(parallel int) {
+}
+
+func (b service) Pause(ctx context.Context, project string, options api.PauseOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Port(ctx context.Context, project string, service string, port uint16, options api.PortOptions) (string, int, error) {
+ return "", 0, api.ErrNotImplemented
+}
+
+func (b service) Ps(ctx context.Context, projectName string, options api.PsOptions) ([]api.ContainerSummary, error) {
+ return nil, api.ErrNotImplemented
+}
+
+func (b service) Publish(ctx context.Context, project *types.Project, repository string, options api.PublishOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Pull(ctx context.Context, project *types.Project, options api.PullOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Push(ctx context.Context, project *types.Project, options api.PushOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Restart(ctx context.Context, projectName string, options api.RestartOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Remove(ctx context.Context, projectName string, options api.RemoveOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) RunOneOffContainer(ctx context.Context, project *types.Project, opts api.RunOptions) (int, error) {
+ return 0, api.ErrNotImplemented
+}
+
+func (b service) Scale(ctx context.Context, project *types.Project, options api.ScaleOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Start(ctx context.Context, projectName string, options api.StartOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Stop(ctx context.Context, projectName string, options api.StopOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Top(ctx context.Context, projectName string, services []string) ([]api.ContainerProcSummary, error) {
+ return nil, api.ErrNotImplemented
+}
+
+func (b service) UnPause(ctx context.Context, project string, options api.PauseOptions) error {
+ return api.ErrNotImplemented
+}
+
+func (b service) Up(ctx context.Context, project *types.Project, _ api.UpOptions) error {
+ template, err := b.Config(ctx, project, api.ConfigOptions{
+ Format: "yaml",
+ })
+ if err != nil {
+ return err
+ }
+
+ if exists, err := b.sdk.StackExists(ctx, project.Name); err != nil {
+ return err
+ } else if !exists {
+ return b.sdk.CreateStack(ctx, project.Name, b.sdk.cfg.Region, template)
+ }
+
+ if changeset, err := b.sdk.CreateChangeSet(ctx, project.Name, b.sdk.cfg.Region, template); err != nil {
+ return err
+ } else {
+ return b.sdk.UpdateStack(ctx, changeset)
+ }
+}
+
+func (b service) Viz(ctx context.Context, project *types.Project, options api.VizOptions) (string, error) {
+ return "", api.ErrNotImplemented
+}
+
+func (b service) Wait(ctx context.Context, projectName string, options api.WaitOptions) (int64, error) {
+ return 0, api.ErrNotImplemented
+}
+
+func (b service) Watch(ctx context.Context, project *types.Project, services []string, options api.WatchOptions) error {
+ return api.ErrNotImplemented
+}
diff --git a/ecs/tags.go b/ecs/tags.go
deleted file mode 100644
index 6449e796..00000000
--- a/ecs/tags.go
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "github.com/awslabs/goformation/v4/cloudformation/tags"
- "github.com/compose-spec/compose-go/types"
- "github.com/docker/compose/v2/pkg/api"
-)
-
-func projectTags(project *types.Project) []tags.Tag {
- return []tags.Tag{
- {
- Key: api.ProjectLabel,
- Value: project.Name,
- },
- }
-}
-
-func serviceTags(project *types.Project, service types.ServiceConfig) []tags.Tag {
- return []tags.Tag{
- {
- Key: api.ProjectLabel,
- Value: project.Name,
- },
- {
- Key: api.ServiceLabel,
- Value: service.Name,
- },
- }
-}
-
-func networkTags(project *types.Project, net types.NetworkConfig) []tags.Tag {
- return []tags.Tag{
- {
- Key: api.ProjectLabel,
- Value: project.Name,
- },
- {
- Key: api.NetworkLabel,
- Value: net.Name,
- },
- }
-}
diff --git a/ecs/testdata/context-by-keys-config.golden b/ecs/testdata/context-by-keys-config.golden
deleted file mode 100644
index 44bfd0d7..00000000
--- a/ecs/testdata/context-by-keys-config.golden
+++ /dev/null
@@ -1,2 +0,0 @@
-[profile default]
-region = eu-west-3
diff --git a/ecs/testdata/context-by-keys-credentials.golden b/ecs/testdata/context-by-keys-credentials.golden
deleted file mode 100644
index a3ac4fe3..00000000
--- a/ecs/testdata/context-by-keys-credentials.golden
+++ /dev/null
@@ -1,3 +0,0 @@
-[default]
-aws_access_key_id = ABCD
-aws_secret_access_key = X&123
diff --git a/ecs/testdata/context-by-profile-config.golden b/ecs/testdata/context-by-profile-config.golden
deleted file mode 100644
index e388f9b0..00000000
--- a/ecs/testdata/context-by-profile-config.golden
+++ /dev/null
@@ -1,3 +0,0 @@
-[profile foo]
-region = eu-west-3
-
diff --git a/ecs/testdata/context-by-profile-credentials.golden b/ecs/testdata/context-by-profile-credentials.golden
deleted file mode 100644
index 7146be5f..00000000
--- a/ecs/testdata/context-by-profile-credentials.golden
+++ /dev/null
@@ -1,4 +0,0 @@
-[foo]
-aws_access_key_id = ABCD
-aws_secret_access_key = X&123
-
diff --git a/ecs/testdata/input/envfile b/ecs/testdata/input/envfile
deleted file mode 100644
index 6ac867af..00000000
--- a/ecs/testdata/input/envfile
+++ /dev/null
@@ -1 +0,0 @@
-FOO=BAR
diff --git a/ecs/testdata/input/simple-single-service.yaml b/ecs/testdata/input/simple-single-service.yaml
deleted file mode 100644
index cf664a43..00000000
--- a/ecs/testdata/input/simple-single-service.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-services:
- simple:
- image: nginx
- ports:
- - "80:80"
\ No newline at end of file
diff --git a/ecs/testdata/invalid_network_mode.yaml b/ecs/testdata/invalid_network_mode.yaml
deleted file mode 100644
index 6e385751..00000000
--- a/ecs/testdata/invalid_network_mode.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-services:
- simple:
- image: nginx
- network_mode: bridge
\ No newline at end of file
diff --git a/ecs/testdata/simple-cloudformation-conversion.golden b/ecs/testdata/simple-cloudformation-conversion.golden
deleted file mode 100644
index 7f82eb5f..00000000
--- a/ecs/testdata/simple-cloudformation-conversion.golden
+++ /dev/null
@@ -1,208 +0,0 @@
-AWSTemplateFormatVersion: 2010-09-09
-Resources:
- CloudMap:
- Properties:
- Description: Service Map for Docker Compose project TestSimpleConvert
- Name: TestSimpleConvert.local
- Vpc: vpc-123
- Type: AWS::ServiceDiscovery::PrivateDnsNamespace
- Cluster:
- Properties:
- ClusterName: TestSimpleConvert
- Tags:
- - Key: com.docker.compose.project
- Value: TestSimpleConvert
- Type: AWS::ECS::Cluster
- Default80Ingress:
- Properties:
- CidrIp: 0.0.0.0/0
- Description: simple:80/tcp on default network
- FromPort: 80
- GroupId:
- Ref: DefaultNetwork
- IpProtocol: TCP
- ToPort: 80
- Type: AWS::EC2::SecurityGroupIngress
- DefaultNetwork:
- Properties:
- GroupDescription: TestSimpleConvert Security Group for default network
- Tags:
- - Key: com.docker.compose.project
- Value: TestSimpleConvert
- - Key: com.docker.compose.network
- Value: TestSimpleConvert_default
- VpcId: vpc-123
- Type: AWS::EC2::SecurityGroup
- DefaultNetworkIngress:
- Properties:
- Description: Allow communication within network default
- GroupId:
- Ref: DefaultNetwork
- IpProtocol: "-1"
- SourceSecurityGroupId:
- Ref: DefaultNetwork
- Type: AWS::EC2::SecurityGroupIngress
- LoadBalancer:
- Properties:
- Scheme: internet-facing
- SecurityGroups:
- - Ref: DefaultNetwork
- Subnets:
- - subnet1
- - subnet2
- Tags:
- - Key: com.docker.compose.project
- Value: TestSimpleConvert
- Type: application
- Type: AWS::ElasticLoadBalancingV2::LoadBalancer
- LogGroup:
- Properties:
- LogGroupName: /docker-compose/TestSimpleConvert
- Type: AWS::Logs::LogGroup
- SimpleService:
- DependsOn:
- - SimpleTCP80Listener
- Properties:
- Cluster:
- Fn::GetAtt:
- - Cluster
- - Arn
- DeploymentConfiguration:
- MaximumPercent: 200
- MinimumHealthyPercent: 100
- DeploymentController:
- Type: ECS
- DesiredCount: 1
- LaunchType: FARGATE
- LoadBalancers:
- - ContainerName: simple
- ContainerPort: 80
- TargetGroupArn:
- Ref: SimpleTCP80TargetGroup
- NetworkConfiguration:
- AwsvpcConfiguration:
- AssignPublicIp: ENABLED
- SecurityGroups:
- - Ref: DefaultNetwork
- Subnets:
- - subnet1
- - subnet2
- PlatformVersion: 1.4.0
- PropagateTags: SERVICE
- SchedulingStrategy: REPLICA
- ServiceRegistries:
- - RegistryArn:
- Fn::GetAtt:
- - SimpleServiceDiscoveryEntry
- - Arn
- Tags:
- - Key: com.docker.compose.project
- Value: TestSimpleConvert
- - Key: com.docker.compose.service
- Value: simple
- TaskDefinition:
- Ref: SimpleTaskDefinition
- Type: AWS::ECS::Service
- SimpleServiceDiscoveryEntry:
- Properties:
- Description: '"simple" service discovery entry in Cloud Map'
- DnsConfig:
- DnsRecords:
- - TTL: 60
- Type: A
- RoutingPolicy: MULTIVALUE
- HealthCheckCustomConfig:
- FailureThreshold: 1
- Name: simple
- NamespaceId:
- Ref: CloudMap
- Type: AWS::ServiceDiscovery::Service
- SimpleTCP80Listener:
- Properties:
- DefaultActions:
- - ForwardConfig:
- TargetGroups:
- - TargetGroupArn:
- Ref: SimpleTCP80TargetGroup
- Type: forward
- LoadBalancerArn:
- Ref: LoadBalancer
- Port: 80
- Protocol: HTTP
- Type: AWS::ElasticLoadBalancingV2::Listener
- SimpleTCP80TargetGroup:
- Properties:
- Port: 80
- Protocol: HTTP
- Tags:
- - Key: com.docker.compose.project
- Value: TestSimpleConvert
- TargetType: ip
- VpcId: vpc-123
- Type: AWS::ElasticLoadBalancingV2::TargetGroup
- SimpleTaskDefinition:
- Properties:
- ContainerDefinitions:
- - Command:
- - .compute.internal
- - TestSimpleConvert.local
- Essential: false
- Image: docker/ecs-searchdomain-sidecar:1.0
- LogConfiguration:
- LogDriver: awslogs
- Options:
- awslogs-group:
- Ref: LogGroup
- awslogs-region:
- Ref: AWS::Region
- awslogs-stream-prefix: TestSimpleConvert
- Name: Simple_ResolvConf_InitContainer
- - DependsOn:
- - Condition: SUCCESS
- ContainerName: Simple_ResolvConf_InitContainer
- Essential: true
- Image: nginx
- LinuxParameters: {}
- LogConfiguration:
- LogDriver: awslogs
- Options:
- awslogs-group:
- Ref: LogGroup
- awslogs-region:
- Ref: AWS::Region
- awslogs-stream-prefix: TestSimpleConvert
- Name: simple
- PortMappings:
- - ContainerPort: 80
- HostPort: 80
- Protocol: tcp
- Cpu: "256"
- ExecutionRoleArn:
- Ref: SimpleTaskExecutionRole
- Family: TestSimpleConvert-simple
- Memory: "512"
- NetworkMode: awsvpc
- RequiresCompatibilities:
- - FARGATE
- Type: AWS::ECS::TaskDefinition
- SimpleTaskExecutionRole:
- Properties:
- AssumeRolePolicyDocument:
- Statement:
- - Action:
- - sts:AssumeRole
- Condition: {}
- Effect: Allow
- Principal:
- Service: ecs-tasks.amazonaws.com
- Version: 2012-10-17
- ManagedPolicyArns:
- - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
- - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
- Tags:
- - Key: com.docker.compose.project
- Value: TestSimpleConvert
- - Key: com.docker.compose.service
- Value: simple
- Type: AWS::IAM::Role
-
diff --git a/ecs/up.go b/ecs/up.go
deleted file mode 100644
index 6779a545..00000000
--- a/ecs/up.go
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
- "fmt"
- "os"
- "os/signal"
- "syscall"
-
- "github.com/compose-spec/compose-go/types"
- "github.com/docker/compose/v2/pkg/api"
- "github.com/docker/compose/v2/pkg/progress"
- "github.com/sirupsen/logrus"
-
- "github.com/docker/compose-ecs/utils"
-)
-
-func (b *ComposeECS) Up(ctx context.Context, project *types.Project, options api.UpOptions) error {
- if err := checkUnsupportedUpOptions(ctx, options); err != nil {
- return err
- }
- return progress.Run(ctx, func(ctx context.Context) error {
- return b.up(ctx, project, options)
- })
-}
-
-func (b *ComposeECS) up(ctx context.Context, project *types.Project, options api.UpOptions) error {
- logrus.Debugf("deploying on AWS with region=%q", b.Region)
- err := b.aws.CheckRequirements(ctx, b.Region)
- if err != nil {
- return err
- }
-
- template, err := b.Convert(ctx, project, api.ConvertOptions{
- Format: "yaml",
- })
- if err != nil {
- return err
- }
-
- update, err := b.aws.StackExists(ctx, project.Name)
- if err != nil {
- return err
- }
-
- var previousEvents []string
- if update {
- var err error
- previousEvents, err = b.previousStackEvents(ctx, project.Name)
- if err != nil {
- return err
- }
- }
-
- operation := stackCreate
- if update {
- operation = stackUpdate
- changeset, err := b.aws.CreateChangeSet(ctx, project.Name, b.Region, template)
- if err != nil {
- return err
- }
- err = b.aws.UpdateStack(ctx, changeset)
- if err != nil {
- return err
- }
- } else {
- err = b.aws.CreateStack(ctx, project.Name, b.Region, template)
- if err != nil {
- return err
- }
- }
- if options.Start.Attach == nil {
- return nil
- }
- signalChan := make(chan os.Signal, 1)
- signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
- go func() {
- <-signalChan
- fmt.Println("user interrupted deployment. Deleting stack...")
- b.Down(ctx, project.Name, api.DownOptions{}) // nolint:errcheck
- }()
-
- err = b.WaitStackCompletion(ctx, project.Name, operation, previousEvents...)
- return err
-}
-
-func checkUnsupportedUpOptions(ctx context.Context, o api.UpOptions) error {
- var errs error
- checks := []struct {
- toCheck, expected interface{}
- option string
- }{
- {o.Create.Inherit, true, "renew-anon-volumes"},
- {o.Create.RemoveOrphans, false, "remove-orphans"},
- {o.Create.QuietPull, false, "quiet-pull"},
- {o.Create.Recreate, api.RecreateDiverged, "force-recreate"},
- {o.Create.RecreateDependencies, api.RecreateDiverged, "always-recreate-deps"},
- {len(o.Start.AttachTo), 0, "attach-dependencies"},
- {len(o.Start.ExitCodeFrom), 0, "exit-code-from"},
- {o.Create.Timeout, nil, "timeout"},
- }
- for _, c := range checks {
- errs = utils.CheckUnsupported(ctx, errs, c.toCheck, c.expected, "up", c.option)
- }
- return errs
-}
diff --git a/ecs/volumes.go b/ecs/volumes.go
deleted file mode 100644
index 7291b96e..00000000
--- a/ecs/volumes.go
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
- "fmt"
-
- "github.com/awslabs/goformation/v4/cloudformation"
- "github.com/awslabs/goformation/v4/cloudformation/efs"
- "github.com/compose-spec/compose-go/types"
- "github.com/docker/compose/v2/pkg/api"
- "github.com/pkg/errors"
-
- "github.com/docker/compose-ecs/api/volumes"
-)
-
-func (b *ComposeECS) createNFSMountTarget(project *types.Project, resources awsResources, template *cloudformation.Template) {
- for volume := range project.Volumes {
- for _, subnet := range resources.subnets {
- name := fmt.Sprintf("%sNFSMountTargetOn%s", normalizeResourceName(volume), normalizeResourceName(subnet.ID()))
- template.Resources[name] = &efs.MountTarget{
- FileSystemId: resources.filesystems[volume].ID(),
- SecurityGroups: resources.allSecurityGroups(),
- SubnetId: subnet.ID(),
- }
- }
- }
-}
-
-func (b *ComposeECS) mountTargets(volume string, resources awsResources) []string {
- var refs []string
- for _, subnet := range resources.subnets {
- refs = append(refs, fmt.Sprintf("%sNFSMountTargetOn%s", normalizeResourceName(volume), normalizeResourceName(subnet.ID())))
- }
- return refs
-}
-
-func (b *ComposeECS) createAccessPoints(project *types.Project, r awsResources, template *cloudformation.Template) {
- for name, volume := range project.Volumes {
- n := fmt.Sprintf("%sAccessPoint", normalizeResourceName(name))
-
- uid := volume.DriverOpts["uid"]
- gid := volume.DriverOpts["gid"]
- permissions := volume.DriverOpts["permissions"]
- path := volume.DriverOpts["root_directory"]
-
- ap := efs.AccessPoint{
- AccessPointTags: []efs.AccessPoint_AccessPointTag{
- {
- Key: api.ProjectLabel,
- Value: project.Name,
- },
- {
- Key: api.VolumeLabel,
- Value: name,
- },
- {
- Key: "Name",
- Value: volume.Name,
- },
- },
- FileSystemId: r.filesystems[name].ID(),
- }
-
- if uid != "" {
- ap.PosixUser = &efs.AccessPoint_PosixUser{
- Uid: uid,
- Gid: gid,
- }
- }
- if path != "" {
- root := efs.AccessPoint_RootDirectory{
- Path: path,
- }
- ap.RootDirectory = &root
- if uid != "" {
- root.CreationInfo = &efs.AccessPoint_CreationInfo{
- OwnerUid: uid,
- OwnerGid: gid,
- Permissions: permissions,
- }
- }
- }
-
- template.Resources[n] = &ap
- }
-}
-
-// VolumeCreateOptions hold EFS filesystem creation options
-type VolumeCreateOptions struct {
- KmsKeyID string
- PerformanceMode string
- ProvisionedThroughputInMibps float64
- ThroughputMode string
-}
-
-type ecsVolumeService struct {
- backend *ComposeECS
-}
-
-func (e ecsVolumeService) List(ctx context.Context) ([]volumes.Volume, error) {
- filesystems, err := e.backend.aws.ListFileSystems(ctx, nil)
- if err != nil {
- return nil, err
- }
- var vol []volumes.Volume
- for _, fs := range filesystems {
- vol = append(vol, volumes.Volume{
- ID: fs.ID(),
- Description: fs.ARN(),
- })
- }
- return vol, nil
-}
-
-func (e ecsVolumeService) Create(ctx context.Context, name string, options interface{}) (volumes.Volume, error) {
- fs, err := e.backend.aws.CreateFileSystem(ctx, map[string]string{
- "Name": name,
- }, options.(VolumeCreateOptions))
- return volumes.Volume{
- ID: fs.ID(),
- Description: fs.ARN(),
- }, err
-
-}
-
-func (e ecsVolumeService) Delete(ctx context.Context, volumeID string, options interface{}) error {
- return e.backend.aws.DeleteFileSystem(ctx, volumeID)
-}
-
-func (e ecsVolumeService) Inspect(ctx context.Context, volumeID string) (volumes.Volume, error) {
- ok, err := e.backend.aws.ResolveFileSystem(ctx, volumeID)
- if ok == nil {
- err = errors.Wrapf(api.ErrNotFound, "filesystem %q does not exists", volumeID)
- }
- return volumes.Volume{
- ID: volumeID,
- Description: ok.ARN(),
- }, err
-}
diff --git a/ecs/wait.go b/ecs/wait.go
deleted file mode 100644
index d305fc11..00000000
--- a/ecs/wait.go
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "context"
- "fmt"
- "sort"
- "strings"
- "time"
-
- "github.com/aws/aws-sdk-go/aws"
- "github.com/docker/compose/v2/pkg/progress"
- "github.com/iancoleman/strcase"
-)
-
-func (b *ComposeECS) WaitStackCompletion(ctx context.Context, name string, operation int, ignored ...string) error { //nolint:gocyclo
- knownEvents := map[string]struct{}{}
- for _, id := range ignored {
- knownEvents[id] = struct{}{}
- }
-
- // progress writer
- w := progress.ContextWriter(ctx)
- // Get the unique Stack ID so we can collect events without getting some from previous deployments with same name
- stackID, err := b.aws.GetStackID(ctx, name)
- if err != nil {
- return err
- }
-
- ticker := time.NewTicker(1 * time.Second)
- done := make(chan bool)
- go func() {
- b.aws.WaitStackComplete(ctx, stackID, operation) //nolint:errcheck
- ticker.Stop()
- done <- true
- }()
-
- var completed bool
- var stackErr error
- for !completed {
- select {
- case <-done:
- completed = true
- case <-ticker.C:
- }
- events, err := b.aws.DescribeStackEvents(ctx, stackID)
- if err != nil {
- return err
- }
-
- sort.Slice(events, func(i, j int) bool {
- return events[i].Timestamp.Before(*events[j].Timestamp)
- })
-
- for _, event := range events {
- if _, ok := knownEvents[*event.EventId]; ok {
- continue
- }
- knownEvents[*event.EventId] = struct{}{}
-
- resource := aws.StringValue(event.LogicalResourceId)
- reason := aws.StringValue(event.ResourceStatusReason)
- status := aws.StringValue(event.ResourceStatus)
- progressStatus := progress.Working
-
- switch status {
- case "CREATE_COMPLETE":
- if operation == stackCreate {
- progressStatus = progress.Done
- }
- case "UPDATE_COMPLETE":
- if operation == stackUpdate {
- progressStatus = progress.Done
- }
- case "DELETE_COMPLETE":
- if operation == stackDelete {
- progressStatus = progress.Done
- }
- default:
- if strings.HasSuffix(status, "_FAILED") {
- progressStatus = progress.Error
- if stackErr == nil {
- operation = stackDelete
- stackErr = fmt.Errorf(reason)
- }
- }
- }
- w.Event(progress.NewEvent(resource, progressStatus, fmt.Sprintf("%s %s", toCamelCase(status), reason)))
- }
- if operation != stackCreate || stackErr != nil {
- continue
- }
- if err := b.checkStackState(ctx, name); err != nil {
- if e := b.aws.DeleteStack(ctx, name); e != nil {
- return e
- }
- stackErr = err
- operation = stackDelete
- w.Event(progress.ErrorMessageEvent(name, err.Error()))
- }
- }
-
- return stackErr
-}
-
-func toCamelCase(status string) string {
- return strcase.ToCamel(strings.ToLower(status))
-}
diff --git a/ecs/wait_test.go b/ecs/wait_test.go
deleted file mode 100644
index a7489655..00000000
--- a/ecs/wait_test.go
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-import (
- "testing"
-
- "gotest.tools/v3/assert"
-)
-
-func TestStatusCamelCase(t *testing.T) {
- assert.Equal(t, toCamelCase("CREATE_IN_PROGRESS"), "CreateInProgress")
-}
diff --git a/ecs/x.go b/ecs/x.go
deleted file mode 100644
index f85cd3f2..00000000
--- a/ecs/x.go
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 ecs
-
-const (
- extensionSecurityGroup = "x-aws-securitygroup"
- extensionVPC = "x-aws-vpc"
- extensionPullCredentials = "x-aws-pull_credentials"
- extensionLoadBalancer = "x-aws-loadbalancer"
- extensionProtocol = "x-aws-protocol"
- extensionCluster = "x-aws-cluster"
- extensionKeys = "x-aws-keys"
- extensionMinPercent = "x-aws-min_percent"
- extensionMaxPercent = "x-aws-max_percent"
- extensionRetention = "x-aws-logs_retention"
- extensionRole = "x-aws-role"
- extensionManagedPolicies = "x-aws-policies"
- extensionAutoScaling = "x-aws-autoscaling"
- extensionCloudFormation = "x-aws-cloudformation"
-)
diff --git a/go.mod b/go.mod
index 3fac91c3..7b4526b4 100644
--- a/go.mod
+++ b/go.mod
@@ -1,120 +1,115 @@
-module github.com/docker/compose-ecs
+module github.com/austindrenski/compose-ecs
-go 1.21
+go 1.22
-toolchain go1.21.5
+toolchain go1.22.0
require (
- github.com/aws/aws-sdk-go v1.44.245
- github.com/awslabs/goformation/v4 v4.15.6
- github.com/cnabio/cnab-to-oci v0.3.1-beta1
- github.com/compose-spec/compose-go v1.20.0
- github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e
+ github.com/aws/aws-sdk-go-v2 v1.24.1
+ github.com/aws/aws-sdk-go-v2/config v1.26.6
+ github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.15
+ github.com/aws/aws-sdk-go-v2/service/cloudformation v1.43.0
+ github.com/aws/aws-sdk-go-v2/service/s3 v1.48.1
+ github.com/awslabs/goformation/v4 v4.19.5
+ github.com/compose-spec/compose-go/v2 v2.0.0-rc.5
github.com/docker/cli v25.0.3+incompatible
github.com/docker/compose/v2 v2.24.5
- github.com/docker/go-units v0.5.0
- github.com/golang/mock v1.6.0
- github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-uuid v1.0.3
- github.com/iancoleman/strcase v0.3.0
- github.com/joho/godotenv v1.3.0
- github.com/opencontainers/go-digest v1.0.0
- github.com/pkg/errors v0.9.1
- github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b
- github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.0
+ golang.org/x/text v0.14.0
gotest.tools/v3 v3.5.1
- sigs.k8s.io/kustomize/kyaml v0.10.15
+ sigs.k8s.io/kustomize/kyaml v0.16.0
)
require (
dario.cat/mergo v1.0.0 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
- github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
- github.com/Masterminds/semver v1.5.0 // indirect
+ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
- github.com/aws/aws-sdk-go-v2 v1.17.6 // indirect
- github.com/aws/aws-sdk-go-v2/config v1.18.16 // indirect
- github.com/aws/aws-sdk-go-v2/credentials v1.13.16 // indirect
- github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 // indirect
- github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 // indirect
- github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 // indirect
- github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 // indirect
- github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 // indirect
- github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 // indirect
- github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 // indirect
- github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 // indirect
- github.com/aws/smithy-go v1.13.5 // indirect
+ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
+ github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect
+ github.com/aws/smithy-go v1.19.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/buger/goterm v1.0.4 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
- github.com/cnabio/cnab-go v0.10.0-beta1 // indirect
- github.com/compose-spec/compose-go/v2 v2.0.0-rc.3 // indirect
- github.com/containerd/console v1.0.3 // indirect
- github.com/containerd/containerd v1.7.12 // indirect
- github.com/containerd/continuity v0.4.2 // indirect
+ github.com/containerd/console v1.0.4 // indirect
+ github.com/containerd/containerd v1.7.13 // indirect
+ github.com/containerd/continuity v0.4.3 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/buildx v0.12.0-rc2.0.20231219140829-617f538cb315 // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
- github.com/docker/docker v25.0.1+incompatible // indirect
- github.com/docker/docker-credential-helpers v0.8.0 // indirect
+ github.com/docker/docker v25.0.3+incompatible // indirect
+ github.com/docker/docker-credential-helpers v0.8.1 // indirect
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
- github.com/emicklei/go-restful/v3 v3.10.1 // indirect
+ github.com/docker/go-units v0.5.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.11.2 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsevents v0.1.1 // indirect
- github.com/fvbommel/sortorder v1.0.2 // indirect
- github.com/go-errors/errors v1.0.1 // indirect
- github.com/go-logr/logr v1.3.0 // indirect
+ github.com/fvbommel/sortorder v1.1.0 // indirect
+ github.com/go-errors/errors v1.5.1 // indirect
+ github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/go-openapi/jsonpointer v0.19.5 // indirect
- github.com/go-openapi/jsonreference v0.20.0 // indirect
- github.com/go-openapi/spec v0.19.5 // indirect
- github.com/go-openapi/swag v0.19.14 // indirect
+ github.com/go-openapi/jsonpointer v0.20.2 // indirect
+ github.com/go-openapi/jsonreference v0.20.4 // indirect
+ github.com/go-openapi/swag v0.22.9 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
- github.com/google/gnostic v0.5.7-v3refs // indirect
+ github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
- github.com/google/uuid v1.5.0 // indirect
+ github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
- github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
+ github.com/gorilla/websocket v1.5.1 // indirect
+ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
- github.com/in-toto/in-toto-golang v0.5.0 // indirect
+ github.com/in-toto/in-toto-golang v0.9.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
- github.com/klauspost/compress v1.17.4 // indirect
- github.com/mailru/easyjson v0.7.6 // indirect
+ github.com/klauspost/compress v1.17.6 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.17 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
- github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
+ github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
- github.com/moby/buildkit v0.13.0-beta1.0.20231219135447-957cb50df991 // indirect
+ github.com/moby/buildkit v0.13.0-beta3 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
@@ -128,82 +123,77 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
- github.com/opentracing/opentracing-go v1.2.0 // indirect
+ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.0-rc6 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_golang v1.16.0 // indirect
- github.com/prometheus/client_model v0.4.0 // indirect
- github.com/prometheus/common v0.42.0 // indirect
- github.com/prometheus/procfs v0.10.1 // indirect
- github.com/qri-io/jsonpointer v0.1.0 // indirect
- github.com/qri-io/jsonschema v0.1.1 // indirect
- github.com/rivo/uniseg v0.2.0 // indirect
+ github.com/prometheus/client_golang v1.18.0 // indirect
+ github.com/prometheus/client_model v0.5.0 // indirect
+ github.com/prometheus/common v0.46.0 // indirect
+ github.com/prometheus/procfs v0.12.0 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
+ github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b // indirect
github.com/sanathkr/yaml v0.0.0-20170819201035-0056894fa522 // indirect
- github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
- github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect
+ github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect
+ github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
- github.com/spf13/viper v1.8.1 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/theupdateframework/notary v0.7.0 // indirect
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 // indirect
- github.com/tonistiigi/fsutil v0.0.0-20230825212630-f09800878302 // indirect
+ github.com/tonistiigi/fsutil v0.0.0-20240208190058-28652255cae4 // indirect
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
- go.opentelemetry.io/otel v1.20.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect
- go.opentelemetry.io/otel/exporters/prometheus v0.42.0 // indirect
- go.opentelemetry.io/otel/metric v1.20.0 // indirect
- go.opentelemetry.io/otel/sdk v1.19.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.19.0 // indirect
- go.opentelemetry.io/otel/trace v1.20.0 // indirect
- go.opentelemetry.io/proto/otlp v1.0.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.48.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 // indirect
+ go.opentelemetry.io/otel v1.23.1 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.23.1 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.23.1 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1 // indirect
+ go.opentelemetry.io/otel/exporters/prometheus v0.45.2 // indirect
+ go.opentelemetry.io/otel/metric v1.23.1 // indirect
+ go.opentelemetry.io/otel/sdk v1.23.1 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.23.1 // indirect
+ go.opentelemetry.io/otel/trace v1.23.1 // indirect
+ go.opentelemetry.io/proto/otlp v1.1.0 // indirect
go.uber.org/mock v0.4.0 // indirect
- golang.org/x/crypto v0.17.0 // indirect
- golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
- golang.org/x/mod v0.11.0 // indirect
- golang.org/x/net v0.17.0 // indirect
- golang.org/x/oauth2 v0.11.0 // indirect
+ golang.org/x/crypto v0.19.0 // indirect
+ golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 // indirect
+ golang.org/x/mod v0.15.0 // indirect
+ golang.org/x/net v0.21.0 // indirect
+ golang.org/x/oauth2 v0.17.0 // indirect
golang.org/x/sync v0.6.0 // indirect
- golang.org/x/sys v0.16.0 // indirect
- golang.org/x/term v0.15.0 // indirect
- golang.org/x/text v0.14.0 // indirect
- golang.org/x/time v0.3.0 // indirect
- golang.org/x/tools v0.10.0 // indirect
- google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
- google.golang.org/grpc v1.59.0 // indirect
- google.golang.org/protobuf v1.31.0 // indirect
+ golang.org/x/sys v0.17.0 // indirect
+ golang.org/x/term v0.17.0 // indirect
+ golang.org/x/time v0.5.0 // indirect
+ golang.org/x/tools v0.18.0 // indirect
+ google.golang.org/appengine v1.6.8 // indirect
+ google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect
+ google.golang.org/grpc v1.61.0 // indirect
+ google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
- gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- k8s.io/api v0.26.7 // indirect
- k8s.io/apimachinery v0.26.7 // indirect
- k8s.io/apiserver v0.26.7 // indirect
- k8s.io/client-go v0.26.7 // indirect
- k8s.io/klog/v2 v2.90.1 // indirect
- k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
- k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect
- sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
- sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
- sigs.k8s.io/yaml v1.3.0 // indirect
+ k8s.io/api v0.29.1 // indirect
+ k8s.io/apimachinery v0.29.1 // indirect
+ k8s.io/apiserver v0.29.1 // indirect
+ k8s.io/client-go v0.29.1 // indirect
+ k8s.io/klog/v2 v2.120.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20240209001042-7a0d5b415232 // indirect
+ k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect
+ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
+ sigs.k8s.io/yaml v1.4.0 // indirect
tags.cncf.io/container-device-interface v0.6.2 // indirect
)
-
-// (for buildx)
-replace github.com/jaguilar/vt100 => github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305
diff --git a/go.sum b/go.sum
index 4cff1464..110b5d71 100644
--- a/go.sum
+++ b/go.sum
@@ -1,277 +1,157 @@
-bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4=
-cloud.google.com/go v0.25.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
-cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
-cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
-cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
-cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
-cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
-cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
-cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
-cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
-cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
-cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
-cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
-cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
-cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
-cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
-cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
-cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
+cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM=
+cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw=
+cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
-cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
-cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
-cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
-cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
-cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
-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-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA=
+github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU=
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
-github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v19.1.1+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-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 v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest v10.15.5+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest v12.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
-github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
-github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
-github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
-github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
-github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
-github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
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/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
-github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
-github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
-github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
-github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
-github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
-github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
-github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-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-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
-github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
-github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
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=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-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/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
-github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/aws/aws-sdk-go v1.15.90/go.mod h1:es1KtYUFs7le0xQ3rOihkuoVD90z7D0fR2Qm4S00/gU=
-github.com/aws/aws-sdk-go v1.34.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
-github.com/aws/aws-sdk-go v1.44.245 h1:KtY2s4q31/kn33AdV63R5t77mdxsI7rq3YT7Mgo805M=
-github.com/aws/aws-sdk-go v1.44.245/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/aws/aws-sdk-go-v2 v1.17.6 h1:Y773UK7OBqhzi5VDXMi1zVGsoj+CVHs2eaC2bDsLwi0=
-github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
-github.com/aws/aws-sdk-go-v2/config v1.18.16 h1:4r7gsCu8Ekwl5iJGE/GmspA2UifqySCCkyyyPFeWs3w=
-github.com/aws/aws-sdk-go-v2/config v1.18.16/go.mod h1:XjM6lVbq7UgELp9NjXBrb1DQY/ownlWsvDhEQksemJc=
-github.com/aws/aws-sdk-go-v2/credentials v1.13.16 h1:GgToSxaENX/1zXIGNFfiVk4hxryYJ5Vt4Mh8XLAL7Lc=
-github.com/aws/aws-sdk-go-v2/credentials v1.13.16/go.mod h1:KP7aFJhfwPFgx9aoVYL2nYHjya5WBD98CWaadpgmnpY=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 h1:5qyqXASrX2zy5cTnoHHa4N2c3Lc94GH7gjnBP3GwKdU=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24/go.mod h1:neYVaeKr5eT7BzwULuG2YbLhzWZ22lpjKdCybR7AXrQ=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 h1:y+8n9AGDjikyXoMBTRaHHHSaFEB8267ykmvyPodJfys=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 h1:r+Kv+SEJquhAZXaJ7G4u44cIwXV3f8K+N482NNAzJZA=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24/go.mod h1:gAuCezX/gob6BSMbItsSlMb6WZGV7K2+fWOvk8xBSto=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 h1:hf+Vhp5WtTdcSdE+yEcUz8L73sAzN0R+0jQv+Z51/mI=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31/go.mod h1:5zUjguZfG5qjhG9/wqmuyHRyUftl2B5Cp6NNxNC6kRA=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 h1:c5qGfdbCHav6viBwiyDns3OXqhqAbGjfIB4uVu2ayhk=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24/go.mod h1:HMA4FZG6fyib+NDo5bpIxX1EhYjrAOveZJY2YR0xrNE=
-github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 h1:bdKIX6SVF3nc3xJFw6Nf0igzS6Ff/louGq8Z6VP/3Hs=
-github.com/aws/aws-sdk-go-v2/service/sso v1.12.5/go.mod h1:vuWiaDB30M/QTC+lI3Wj6S/zb7tpUK2MSYgy3Guh2L0=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 h1:xLPZMyuZ4GuqRCIec/zWuIhRFPXh2UOJdLXBSi64ZWQ=
-github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5/go.mod h1:QjxpHmCwAg0ESGtPQnLIVp7SedTOBMYy+Slr3IfMKeI=
-github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 h1:rIFn5J3yDoeuKCE9sESXqM5POTAhOP1du3bv/qTL+tE=
-github.com/aws/aws-sdk-go-v2/service/sts v1.18.6/go.mod h1:48WJ9l3dwP0GSHWGc5sFGGlCkuA82Mc2xnw+T6Q8aDw=
-github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
-github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
-github.com/awslabs/goformation/v4 v4.15.6 h1:9F0MbtJVSMkuI19G6Fm+qHc1nqScHcOIf+3YRRv+Ohc=
-github.com/awslabs/goformation/v4 v4.15.6/go.mod h1:wB5lKZf1J0MYH1Lt4B9w3opqz0uIjP7MMCAcib3QkwA=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU=
+github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo=
+github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o=
+github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4=
+github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8=
+github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.15 h1:2MUXyGW6dVaQz6aqycpbdLIH1NMcUI6kW6vQ0RabGYg=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.15/go.mod h1:aHbhbR6WEQgHAiRj41EQ2W47yOYwNtIkWTXmcAtYqj8=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 h1:5oE2WzJE56/mVveuDZPJESKlg/00AaS2pY2QZcnxg4M=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10/go.mod h1:FHbKWQtRBYUz4vO5WBWjzMD2by126ny5y/1EoaWoLfI=
+github.com/aws/aws-sdk-go-v2/service/cloudformation v1.43.0 h1:fusTelL7ZIvR51E+xwc/HVUlWGhkWFlS+dtYrynVBq4=
+github.com/aws/aws-sdk-go-v2/service/cloudformation v1.43.0/go.mod h1:3+AceTAg/X5AUM/SkAbgxzviOBmsGaf9POso/Ymz5vc=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10 h1:L0ai8WICYHozIKK+OtPzVJBugL7culcuM4E4JOpIEm8=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10/go.mod h1:byqfyxJBshFk0fF9YmK0M0ugIO8OWjzH2T3bPG4eGuA=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10 h1:KOxnQeWy5sXyS37fdKEvAsGHOr9fa/qvwxfJurR/BzE=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10/go.mod h1:jMx5INQFYFYB3lQD9W0D8Ohgq6Wnl7NYOJ2TQndbulI=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.48.1 h1:5XNlsBsEvBZBMO6p82y+sqpWg8j5aBCe+5C2GBFgqBQ=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.48.1/go.mod h1:4qXHrG1Ne3VGIMZPCB8OjH/pLFO94sKABIusjh0KWPU=
+github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow=
+github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8=
+github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0=
+github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U=
+github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM=
+github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE=
+github.com/awslabs/goformation/v4 v4.19.5 h1:Y+Tzh01tWg8gf//AgGKUamaja7Wx9NPiJf1FpZu4/iU=
+github.com/awslabs/goformation/v4 v4.19.5/go.mod h1:JoNpnVCBOUtEz9bFxc9sjy8uBUCLF5c4D1L7RhRTVM8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
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-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
-github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
-github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
+github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0 h1:s7+5BfS4WFJoVF9pnB8kBk03S7pZXRdKamnV0FOl5Sc=
github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
-github.com/bugsnag/bugsnag-go v1.5.0 h1:tP8hiPv1pGGW3LA6LKy5lW6WG+y9J2xWUdPd3WC452k=
-github.com/bugsnag/bugsnag-go v1.5.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
+github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
+github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA=
-github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY=
+github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ=
github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
-github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiKw=
-github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo=
-github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4=
-github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo=
-github.com/cnabio/cnab-go v0.10.0-beta1 h1:5LEEODVQkyCHfeT6pggPz5zq/PinA/CzlNrChFkfGkg=
-github.com/cnabio/cnab-go v0.10.0-beta1/go.mod h1:5c4uOP6ZppR4nUGtCMAElscRiYEUi44vNQwtSAvISXk=
-github.com/cnabio/cnab-to-oci v0.3.1-beta1 h1:qAuLRt+2J7U7wIB5YG+COtS630NQCf4G1h1p0Yk6llo=
-github.com/cnabio/cnab-to-oci v0.3.1-beta1/go.mod h1:8BomA5Vye+3V/Kd2NSFblCBmp1rJV5NfXBYKbIGT5Rw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
+github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
+github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
-github.com/compose-spec/compose-go v1.20.0 h1:h4ZKOst1EF/DwZp7dWkb+wbTVE4nEyT9Lc89to84Ol4=
-github.com/compose-spec/compose-go v1.20.0/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM=
-github.com/compose-spec/compose-go/v2 v2.0.0-rc.3 h1:t0qajSNkH3zR4HEN2CM+GVU7GBx5AwqiYJk5w800M7w=
-github.com/compose-spec/compose-go/v2 v2.0.0-rc.3/go.mod h1:r7CJHU0GaLtRVLm2ch8RCNkJh3GHyaqqc2rSti7VP44=
+github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
+github.com/compose-spec/compose-go/v2 v2.0.0-rc.5 h1:YoGsuVzxve1m5SdCfZqI8wJoMVZWu7SelHoqiCqb+iQ=
+github.com/compose-spec/compose-go/v2 v2.0.0-rc.5/go.mod h1:bEPizBkIojlQ20pi2vNluBa58tevvj0Y18oUSHPyfdc=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
-github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
-github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
-github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
-github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk=
-github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
-github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
-github.com/containerd/fifo v0.0.0-20190816180239-bda0ff6ed73c/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
+github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
+github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
+github.com/containerd/containerd v1.7.13 h1:wPYKIeGMN8vaggSKuV1X0wZulpMz4CrgEsZdaCyB6Is=
+github.com/containerd/containerd v1.7.13/go.mod h1:zT3up6yTRfEUa6+GsITYIJNgSVL9NQ4x4h1RPzk0Wu4=
+github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
+github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
+github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/nydus-snapshotter v0.13.1 h1:5XNkCZ9ivLXCcyx3Jbbfh/fntkcls69uBg0x9VE8zlk=
+github.com/containerd/nydus-snapshotter v0.13.1/go.mod h1:XWAz9ytsjBuKPVXDKP3xoMlcSKNsGnjXlEup6DuzUIo=
github.com/containerd/stargz-snapshotter v0.14.3 h1:OTUVZoPSPs8mGgmQUE1dqw3WX/3nrsmsurW7UPLWl1U=
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
-github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
+github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
github.com/containerd/ttrpc v1.2.2 h1:9vqZr0pxwOF5koz6N0N3kJ0zDHokrcPxIR/ZR2YFtOs=
-github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
+github.com/containerd/ttrpc v1.2.2/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak=
github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0=
-github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
-github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
-github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
-github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
-github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
-github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e h1:n81KvOMrLZa+VWHwST7dun9f0G98X3zREHS1ztYzZKU=
-github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e/go.mod h1:xpWTC2KnJMiDLkoawhsPQcXjvwATEBcbq0xevG2YR9M=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/buildx v0.12.0-rc2.0.20231219140829-617f538cb315 h1:UZxx9xBADdf/9UmSdEUi+pdJoPKpgcf9QUAY5gEIYmY=
github.com/docker/buildx v0.12.0-rc2.0.20231219140829-617f538cb315/go.mod h1:X8ZHhuW6ncwtoJ36TlU+gyaROTcBkTE01VHYmTStQCE=
-github.com/docker/cli v0.0.0-20190925022749-754388324470/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v25.0.3+incompatible h1:KLeNs7zws74oFuVhgZQ5ONGZiXUUdgsdy6/EsX/6284=
github.com/docker/cli v25.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/compose/v2 v2.24.5 h1:7K173fhy+ghA88C8ib5YNa+kAZCx0CBeGW7lHcdoPZw=
github.com/docker/compose/v2 v2.24.5/go.mod h1:gg+RsqCXYD/TOIJgya4N9mtj/UmFJGEls7y3h/kadVE=
-github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v1.4.2-0.20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v1.4.2-0.20181229214054-f76d6a078d88/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v25.0.1+incompatible h1:k5TYd5rIVQRSqcTwCID+cyVA0yRg86+Pcrz1ls0/frA=
-github.com/docker/docker v25.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
-github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
-github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
-github.com/docker/go v1.5.1-1/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
+github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ=
+github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
+github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
@@ -280,439 +160,207 @@ github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
-github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
-github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/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/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
-github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
-github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
-github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU=
+github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
+github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
-github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsevents v0.1.1 h1:/125uxJvvoSDDBPen6yUZbil8J9ydKZnnl3TWWmvnkw=
github.com/fsnotify/fsevents v0.1.1/go.mod h1:+d+hS27T6k5J8CRaPLKFgwKYcpS7GwW3Ule9+SC2ZRc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
-github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
-github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
-github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
+github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
+github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
+github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
-github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
-github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
-github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
-github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
-github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
-github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
-github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
-github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
-github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
-github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
-github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
-github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
-github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
-github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
-github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
-github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
-github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
-github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
-github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
-github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
-github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
-github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
-github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
-github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
-github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
-github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
-github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
-github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw=
-github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
-github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
-github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
-github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
-github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
-github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
-github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
-github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
-github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
-github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
-github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
-github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
+github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
+github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
+github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
+github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
+github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
+github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
+github.com/go-sql-driver/mysql v1.3.0 h1:pgwjLi/dvffoP9aabwkT3AKpXQM93QARkjFhDDqC1UE=
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
-github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
-github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
-github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
-github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
-github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
-github.com/gogo/googleapis v1.3.0/go.mod h1:d+q1s/xVJxZGKWwC/6UfPIF33J+G1Tq4GYv9Y+Tg/EU=
github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
-github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-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=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
-github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
-github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
-github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
-github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
-github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-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/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93 h1:jc2UWq7CbdszqeH6qu1ougXMIUBfSy8Pbh/anURYbGI=
github.com/google/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
-github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
-github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
-github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
-github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
+github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU=
+github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-containerregistry v0.0.0-20191015185424-71da34e4d9b3/go.mod h1:ZXFeSndFcK4vB1NR4voH1Zm38K7ViUNiYtfIBDxrwf0=
-github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
-github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
-github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
-github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
-github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
-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/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-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/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
-github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
-github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
-github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
+github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
+github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
-github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-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/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=
-github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
-github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
-github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
-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.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
-github.com/in-toto/in-toto-golang v0.5.0 h1:hb8bgwr0M2hGdDsLjkJ3ZqJ8JFLL/tgYdAxF/XEFBbY=
-github.com/in-toto/in-toto-golang v0.5.0/go.mod h1:/Rq0IZHLV7Ku5gielPT4wPHJfH1GdHMCq8+WPxw8/BE=
+github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU=
+github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8 h1:CZkYfurY6KGhVtlalI4QwQ6T0Cu6iuY3e0x5RLu96WE=
github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
-github.com/jinzhu/gorm v1.9.11 h1:gaHGvE+UnWGlbWG4Y3FUwY1EcZ5n6S9WtqBA/uySMLE=
-github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw=
+github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d h1:jRQLvyVGL+iVtDElaEIDdKwpPqUIZJfzkNLV34htpEc=
github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
-github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
-github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
-github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
-github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo=
-github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
-github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
-github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
-github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
-github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw=
-github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
-github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
+github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
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=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c=
github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/magiconair/properties v1.5.3 h1:C8fxWnhYyME3n0klPOhVM7PtYUB3eV1W3DeFmN3j53Y=
github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
-github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
-github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
-github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
-github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
-github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
-github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
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/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
-github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
+github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
-github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
-github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-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-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
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/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/moby/buildkit v0.13.0-beta1.0.20231219135447-957cb50df991 h1:r80LLQ91uOLxU1ElAvrB1o8oBsph51lPzVnr7t2b200=
-github.com/moby/buildkit v0.13.0-beta1.0.20231219135447-957cb50df991/go.mod h1:6MddWPSL5jxy+W8eMMHWDOfZzzRRKWXPZqajw72YHBc=
+github.com/moby/buildkit v0.13.0-beta3 h1:eefOGE6SsWYHFfymc09Q7VU5i3L9vUs8ZCZVCDXWNOo=
+github.com/moby/buildkit v0.13.0-beta3/go.mod h1:tSWWhq1EDM0eB3ngMNDiH2hOOW9fXTyn2uXuOraCLlE=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
@@ -734,7 +382,6 @@ github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
@@ -743,183 +390,110 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
-github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
-github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
-github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
-github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/ginkgo v1.16.2 h1:HFB2fbVIlhIfCfOW81bZFbiC/RvnpXSdhbF2/DJr134=
+github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
+github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
+github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
-github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
-github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/onsi/gomega v1.12.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
+github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
+github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/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 v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
-github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
-github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU=
+github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
+github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
+github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
+github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
-github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pivotal/image-relocation v0.0.0-20191111101224-e94aff6df06c/go.mod h1:/JNbQwGylYm3AQh8q+MBF8e/h0W1Jy20JGTvozuXYTE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
-github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
-github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
-github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
+github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
+github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/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=
-github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
-github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
-github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
-github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
+github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
+github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
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-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
-github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
-github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/qri-io/jsonpointer v0.1.0 h1:OcTtTmorodUCRc2CZhj/ZwOET8zVj6uo0ArEmzoThZI=
-github.com/qri-io/jsonpointer v0.1.0/go.mod h1:DnJPaYgiKu56EuDp8TU5wFLdZIcAnb/uH9v37ZaMV64=
-github.com/qri-io/jsonschema v0.1.1 h1:t//Doa/gvMqJ0bDhG7PGIKfaWGGxRVaffp+bcvBGGEk=
-github.com/qri-io/jsonschema v0.1.1/go.mod h1:QpzJ6gBQ0GYgGmh7mDQ1YsvvhSgE4rYj0k8t5MBOmUY=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b h1:jUK33OXuZP/l6babJtnLo1qsGvq6G9so9KMflGAm4YA=
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b/go.mod h1:8458kAagoME2+LN5//WxE71ysZ3B7r22fdgb7qVmXSY=
github.com/sanathkr/yaml v0.0.0-20170819201035-0056894fa522 h1:fOCp11H0yuyAt2wqlbJtbyPzSgaxHTv8uN1pMpkG1t8=
github.com/sanathkr/yaml v0.0.0-20170819201035-0056894fa522/go.mod h1:tQTYKOQgxoH3v6dEmdHiz4JG+nbxWwM5fgPQUpSZqVQ=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
-github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
-github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
-github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 h1:ka9QPuQg2u4LGipiZGsgkg3rJCo4iIUCy75FddM0GRQ=
-github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc=
+github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbmfHkLguCE9laoZCUzEEpIZXA=
+github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU=
+github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b h1:h+3JX2VoWTFuyQEo87pStk/a99dzIO1mM9KxIyLPGTU=
+github.com/serialx/hashring v0.0.0-20200727003509-22c0c7ab6b1b/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc=
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
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.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spdx/tools-golang v0.5.1 h1:fJg3SVOGG+eIva9ZUBm/hvyA7PIPVFjRxUKe6fdAgwE=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
-github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
-github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
+github.com/spdx/tools-golang v0.5.1/go.mod h1:/DRDQuBfB37HctM29YtrX1v+bXiVmT2OpQDalRmX9aU=
+github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94 h1:JmfC365KywYwHB946TTiQWEb8kqPY+pybPLoGE9GgVk=
github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
-github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
+github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431 h1:XTHrT015sxHyJ5FnQ0AeemSspZWaDq7DoTRW0EVsDCE=
github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
-github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
-github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c h1:2EejZtjFjKJGk71ANb+wtFK5EjUzUkEM3R0xnp559xg=
github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
-github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
-github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
-github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
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/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
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=
@@ -928,32 +502,18 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-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-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/theupdateframework/notary v0.6.1/go.mod h1:MOfgIfmox8s7/7fduvB2xyPPMJCrjRLRizA8OFwpnKY=
github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
-github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 h1:QB54BJwA6x8QU9nHY3xJSZR2kX9bgpZekRKGkLTmEXA=
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375/go.mod h1:xRroudyp5iVtxKqZCrA6n2TLFRBf8bmnjr1UD4x+z7g=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tonistiigi/fsutil v0.0.0-20230825212630-f09800878302 h1:ZT8ibgassurSISJ1Pj26NsM3vY2jxFZn63Nd/TpHmRw=
-github.com/tonistiigi/fsutil v0.0.0-20230825212630-f09800878302/go.mod h1:9kMVqMyQ/Sx2df5LtnGG+nbrmiZzCS7V6gjW3oGHsvI=
+github.com/tonistiigi/fsutil v0.0.0-20240208190058-28652255cae4 h1:OE/5jFYeM2WgeDvtZe+9OKSJKFFxWH5vtLh/1/42c4E=
+github.com/tonistiigi/fsutil v0.0.0-20240208190058-28652255cae4/go.mod h1:9kMVqMyQ/Sx2df5LtnGG+nbrmiZzCS7V6gjW3oGHsvI=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea h1:SXhTLE6pb6eld/v/cCndK0AMpt1wiVFb/YYmqB3/QG0=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk=
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 h1:Y/M5lygoNPKwVNLMPXgVfsRT40CSFKXCxuU8LoHySjs=
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531/go.mod h1:ulncasL3N9uLrVann0m+CDlJKWsIAP34MPcOJF6VRvc=
-github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
-github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck=
-github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
-github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
-github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU=
-github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
+github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
+github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -962,293 +522,121 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
-github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
-github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
+github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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=
-github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
-github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
-github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
-github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e h1:mvOa4+/DXStR4ZXOks/UsjeFdn5O5JpLUtzqk9U8xXw=
-github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8=
-github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb h1:vxqkjztXSaPVDc8FQCdHTaejm2x747f6yPbnu1h2xkg=
-github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY=
-go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
-go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
-go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
-go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
-go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0 h1:2ea0IkZBsWH+HA2GkD+7+hRw2u97jzdFyRtXuO14a1s=
-go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.45.0/go.mod h1:4m3RnBBb+7dB9d21y510oO1pdB1V4J6smNf14WXcBFQ=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q=
-go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc=
-go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:NmnYCiR0qNufkldjVvyQfZTHSdzeHoZ41zggMsdMcLM=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
-go.opentelemetry.io/otel/exporters/prometheus v0.42.0 h1:jwV9iQdvp38fxXi8ZC+lNpxjK16MRcZlpDYvbuO1FiA=
-go.opentelemetry.io/otel/exporters/prometheus v0.42.0/go.mod h1:f3bYiqNqhoPxkvI2LrXqQVC546K7BuRDL/kKuxkujhA=
-go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA=
-go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM=
-go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
-go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
-go.opentelemetry.io/otel/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k=
-go.opentelemetry.io/otel/sdk/metric v1.19.0/go.mod h1:XjG0jQyFJrv2PbMvwND7LwCEhsJzCzV5210euduKcKY=
-go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ=
-go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU=
-go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
-go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
-go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 h1:P+/g8GpuJGYbOp2tAdKrIPUX9JO02q8Q0YNlHolpibA=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.48.0 h1:ZeW4++xt1VrFSdnd0pFXz0PkrjLb89/VPOUOyPDJG/g=
+go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.48.0/go.mod h1:ZdzuQW6m/OEtOLWWJs+k5ddZXsUq9xs2vx+ZT9G9eJ0=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+ExOpH3spVTLS0FcWGLnQrPct/hD/bCPbDRUEAU=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA=
+go.opentelemetry.io/otel v1.23.1 h1:Za4UzOqJYS+MUczKI320AtqZHZb7EqxO00jAHE0jmQY=
+go.opentelemetry.io/otel v1.23.1/go.mod h1:Td0134eafDLcTS4y+zQ26GE8u3dEuRBiBCTUIRHaikA=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.23.1 h1:ZqRWZJGHXV/1yCcEEVJ6/Uz2JtM79DNS8OZYa3vVY/A=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.23.1/go.mod h1:D7ynngPWlGJrqyGSDOdscuv7uqttfCE3jcBvffDv9y4=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.23.1 h1:q/Nj5/2TZRIt6PderQ9oU0M00fzoe8UZuINGw6ETGTw=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.23.1/go.mod h1:DTE9yAu6r08jU3xa68GiSeI7oRcSEQ2RpKbbQGO+dWM=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 h1:o8iWeVFa1BcLtVEV0LzrCxV2/55tB3xLxADr6Kyoey4=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1/go.mod h1:SEVfdK4IoBnbT2FXNM/k8yC08MrfbhWk3U4ljM8B3HE=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1 h1:p3A5+f5l9e/kuEBwLOrnpkIDHQFlHmbiVxMURWRK6gQ=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1/go.mod h1:OClrnXUjBqQbInvjJFjYSnMxBSCXBF8r3b34WqjiIrQ=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1 h1:cfuy3bXmLJS7M1RZmAL6SuhGtKUp2KEsrm00OlAXkq4=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1/go.mod h1:22jr92C6KwlwItJmQzfixzQM3oyyuYLCfHiMY+rpsPU=
+go.opentelemetry.io/otel/exporters/prometheus v0.45.2 h1:pe2Jqk1K18As0RCw7J08QhgXNqr+6npx0a5W4IgAFA8=
+go.opentelemetry.io/otel/exporters/prometheus v0.45.2/go.mod h1:B38pscHKI6bhFS44FDw0eFU3iqG3ASNIvY+fZgR5sAc=
+go.opentelemetry.io/otel/metric v1.23.1 h1:PQJmqJ9u2QaJLBOELl1cxIdPcpbwzbkjfEyelTl2rlo=
+go.opentelemetry.io/otel/metric v1.23.1/go.mod h1:mpG2QPlAfnK8yNhNJAxDZruU9Y1/HubbC+KyH8FaCWI=
+go.opentelemetry.io/otel/sdk v1.23.1 h1:O7JmZw0h76if63LQdsBMKQDWNb5oEcOThG9IrxscV+E=
+go.opentelemetry.io/otel/sdk v1.23.1/go.mod h1:LzdEVR5am1uKOOwfBWFef2DCi1nu3SA8XQxx2IerWFk=
+go.opentelemetry.io/otel/sdk/metric v1.23.1 h1:T9/8WsYg+ZqIpMWwdISVVrlGb/N0Jr1OHjR/alpKwzg=
+go.opentelemetry.io/otel/sdk/metric v1.23.1/go.mod h1:8WX6WnNtHCgUruJ4TJ+UssQjMtpxkpX0zveQC8JG/E0=
+go.opentelemetry.io/otel/trace v1.23.1 h1:4LrmmEd8AU2rFvU1zegmvqW7+kWarxtNOPyeL6HmYY8=
+go.opentelemetry.io/otel/trace v1.23.1/go.mod h1:4IpnpJFwr1mo/6HL8XIPJaE9y0+u1KcVmuW7dwFSVrI=
+go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
+go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
-golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
-golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo=
+golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
-golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
-golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
+golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
-golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
-golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
-golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
-golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
+golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ=
+golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190830141801-acfa387b8d69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1258,325 +646,126 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
-golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
-golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
-golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
+golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
-golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191014205221-18e3458ac98b/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
-golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
-golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
+golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
+golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
-google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
-google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
-google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
-google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
-google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
-google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-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 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
-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/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
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-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
-google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
-google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
-google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
-google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
-google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
-google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
-google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU=
+google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M=
+google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A=
+google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4=
google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-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.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
-google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
-google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
+google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
+google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
+google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/dancannon/gorethink.v3 v3.0.5/go.mod h1:GXsi1e3N2OcKhcP6nsYABTiUejbWMFO4GY5a4pEaeEc=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
-gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I=
-gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
-gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1 h1:d4KQkxAaAiRY2h5Zqis161Pv91A37uZyJOx73duwUwM=
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1/go.mod h1:WbjuEoo1oadwzQ4apSDU+JTvmllEHtsNHS6y7vFc7iw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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/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.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
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=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
-k8s.io/api v0.0.0-20191016110408-35e52d86657a/go.mod h1:/L5qH+AD540e7Cetbui1tuJeXdmNhO8jM6VkXeDdDhQ=
-k8s.io/api v0.26.7 h1:Lf4iEBEJb5OFNmawtBfSZV/UNi9riSJ0t1qdhyZqI40=
-k8s.io/api v0.26.7/go.mod h1:Vk9bMadzA49UHPmHB//lX7VRCQSXGoVwfLd3Sc1SSXI=
-k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
-k8s.io/apimachinery v0.0.0-20190806215851-162a2dabc72f/go.mod h1:+ntn62igV2hyNj7/0brOvXSMONE2KxcePkSxK7/9FFQ=
-k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ=
-k8s.io/apimachinery v0.26.7 h1:590jSBwaSHCAFCqltaEogY/zybFlhGsnLteLpuF2wig=
-k8s.io/apimachinery v0.26.7/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0=
-k8s.io/apiserver v0.26.7 h1:NX/zBZZn4R+Cq6shwyn8Pn8REd0yJJ16dbtv9WkEVEU=
-k8s.io/apiserver v0.26.7/go.mod h1:r0wDRWHI7VL/KlQLTkJJBVGZ3KeNfv+VetlyRtr86xs=
-k8s.io/client-go v0.0.0-20180910083459-2cefa64ff137/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
-k8s.io/client-go v0.0.0-20191016111102-bec269661e48/go.mod h1:hrwktSwYGI4JK+TJA3dMaFyyvHVi/aLarVHpbs8bgCU=
-k8s.io/client-go v0.26.7 h1:hyU9aKHlwVOykgyxzGYkrDSLCc4+mimZVyUJjPyUn1E=
-k8s.io/client-go v0.26.7/go.mod h1:okYjy0jtq6sdeztALDvCh24tg4opOQS1XNvsJlERDAo=
-k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
-k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
-k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
-k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
-k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
-k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
-k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
-k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
-k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
-k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
-k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk=
-k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
-sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
-sigs.k8s.io/kustomize/kyaml v0.10.15 h1:dSLgG78KyaxN4HylPXdK+7zB3k7sW6q3IcCmcfKA+aI=
-sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg=
-sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
-sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
-sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
-sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
-sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
-sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
+k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw=
+k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ=
+k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc=
+k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU=
+k8s.io/apiserver v0.29.1 h1:e2wwHUfEmMsa8+cuft8MT56+16EONIEK8A/gpBSco+g=
+k8s.io/apiserver v0.29.1/go.mod h1:V0EpkTRrJymyVT3M49we8uh2RvXf7fWC5XLB0P3SwRw=
+k8s.io/client-go v0.29.1 h1:19B/+2NGEwnFLzt0uB5kNJnfTsbV8w6TgQRz9l7ti7A=
+k8s.io/client-go v0.29.1/go.mod h1:TDG/psL9hdet0TI9mGyHJSgRkW3H9JZk2dNEUS7bRks=
+k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
+k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/kube-openapi v0.0.0-20240209001042-7a0d5b415232 h1:MMq4iF9pHuAz/9dLnHwBQKEoeigXClzs3MFh/seyqtA=
+k8s.io/kube-openapi v0.0.0-20240209001042-7a0d5b415232/go.mod h1:Pa1PvrP7ACSkuX6I7KYomY6cmMA0Tx86waBhDUgoKPw=
+k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ=
+k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/kustomize/kyaml v0.16.0 h1:6J33uKSoATlKZH16unr2XOhDI+otoe2sR3M8PDzW3K0=
+sigs.k8s.io/kustomize/kyaml v0.16.0/go.mod h1:xOK/7i+vmE14N2FdFyugIshB8eF6ALpy7jI87Q2nRh4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
tags.cncf.io/container-device-interface v0.6.2 h1:dThE6dtp/93ZDGhqaED2Pu374SOeUkBfuvkLuiTdwzg=
tags.cncf.io/container-device-interface v0.6.2/go.mod h1:Shusyhjs1A5Na/kqPVLL0KqnHQHuunol9LFeUNkuGVE=
-vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=
diff --git a/internal/variables.go b/internal/variables.go
deleted file mode 100644
index 8be6ce1b..00000000
--- a/internal/variables.go
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 internal
-
-var (
- // Version is the version of the CLI injected at compilation time
- Version = "dev"
-)
diff --git a/packaging/LICENSE b/packaging/LICENSE
deleted file mode 100644
index fcf6aa89..00000000
--- a/packaging/LICENSE
+++ /dev/null
@@ -1,2 +0,0 @@
-The Docker End User License Agreement (https://www.docker.com/legal/docker-software-end-user-license-agreement) describes Docker's Terms for this software.
-By downloading, accessing, or using this software you expressly accept and agree to the Terms set out in the Docker End User License Agreement.
diff --git a/samples/compose.ecs.yml b/samples/compose.ecs.yml
new file mode 100644
index 00000000..7a80ea2d
--- /dev/null
+++ b/samples/compose.ecs.yml
@@ -0,0 +1,74 @@
+services:
+ otel:
+ deploy:
+ replicas: 10
+ secrets:
+ - DD_API_KEY
+ x-aws-pull_credentials: &x-aws-pull_credentials ${AWS_PULL_CREDENTIALS_ARN}
+
+ some_service:
+ deploy:
+ resources:
+ limits:
+ cpus: '1.00'
+ memory: 2g
+ dns_search:
+ - ${COMPOSE_PROJECT}.local
+ environment:
+ DOTNET_gcServer: ${DOTNET_gcServer:-0}
+ secrets:
+ - SomeOptions__Token
+ ulimits:
+ nofile:
+ soft: 65535
+ hard: 65535
+ x-aws-pull_credentials: *x-aws-pull_credentials
+ x-aws-role:
+ Version: 2012-10-17
+ Statement:
+ - Action:
+ - s3:GetObject
+ Effect: Allow
+ Resource:
+ - arn:aws:s3:::some-bucket
+
+secrets:
+ DD_API_KEY:
+ external: true
+ name: ${DD_API_KEY_ARN}
+ SomeOptions__Token:
+ external: true
+ name: ${SOME_OPTIONS_TOKEN_ARN}
+
+x-aws-loadbalancer: ${AWS_LOAD_BALANCER_ARN}
+x-aws-subnets:
+- ${AWS_SUBNET_ID_A}
+- ${AWS_SUBNET_ID_B}
+- ${AWS_SUBNET_ID_C}
+x-aws-vpc: ${AWS_VPC_ID}
+
+x-aws-cloudformation:
+ Resources:
+ OtelTCP4318TargetGroup:
+ Properties:
+ HealthCheckPort: &otel-health-check-port 13133
+ TargetGroupAttributes: &target-group-attributes
+ - Key: deregistration_delay.timeout_seconds
+ Value: 5
+ OtelTCP13133TargetGroup:
+ Properties:
+ HealthCheckPort: *otel-health-check-port
+ TargetGroupAttributes: *target-group-attributes
+ OtelTCP55679TargetGroup:
+ Properties:
+ HealthCheckPort: *otel-health-check-port
+ TargetGroupAttributes: *target-group-attributes
+ SomeServiceTCP8080Listener:
+ Properties:
+ Certificates:
+ - CertificateArn: ${AWS_CERTIFICATE_ARN}
+ Port: 443
+ Protocol: TLS
+ SomeServiceTCP8080TargetGroup:
+ Properties:
+ TargetGroupAttributes: *target-group-attributes
diff --git a/samples/compose.local.yml b/samples/compose.local.yml
new file mode 100644
index 00000000..55e2594f
--- /dev/null
+++ b/samples/compose.local.yml
@@ -0,0 +1,22 @@
+services:
+ localstack:
+ image: localstack/localstack
+ ports:
+ - 4566:4566
+ - 4510-4559:4510-4559
+
+ otel:
+ secrets:
+ - DD_API_KEY
+
+ some_service:
+ ports:
+ - 80:8080
+ secrets:
+ - SomeOptions__Token
+
+secrets:
+ DD_API_KEY:
+ file: ~/.dd-api-key
+ SomeOptions__Token:
+ file: ~/.some-options-token
diff --git a/samples/compose.yml b/samples/compose.yml
new file mode 100644
index 00000000..191afd53
--- /dev/null
+++ b/samples/compose.yml
@@ -0,0 +1,27 @@
+services:
+ otel:
+ environment:
+ OTEL_DEBUG_VERBOSITY: normal
+ OTEL_DEPLOYMENT_ENVIRONMENT: dev
+ OTEL_SAMPLING_PERCENTAGE: 100
+ image: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib:latest
+ ports:
+ - 4318
+ - 13133
+ - 55679
+
+ some_service:
+ depends_on:
+ otel:
+ condition: service_started
+ environment:
+ OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES: true
+ OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES: true
+ OTEL_EXPORTER_OTLP_ENDPOINT: http://otel:4318
+ OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
+ OTEL_SEMCONV_STABILITY_OPT_IN: http
+ healthcheck:
+ test: wget -t1 -qO- http://localhost:8080/health
+ image: ghcr.io/austindrenski/some_service:latest
+ ports:
+ - 8080
diff --git a/scripts/install/install_linux.sh b/scripts/install/install_linux.sh
deleted file mode 100644
index b1f20a3f..00000000
--- a/scripts/install/install_linux.sh
+++ /dev/null
@@ -1,213 +0,0 @@
-#!/bin/sh
-
-# Copyright 2020 Docker Compose CLI authors
-
-# 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.
-
-# Script to install the Docker Compose CLI on Ubuntu (Beta).
-
-set -eu
-
-RELEASE_URL=https://api.github.com/repos/docker/compose-ecs/releases/latest
-LINK_NAME="${LINK_NAME:-com.docker.cli}"
-DRY_RUN="${DRY_RUN:-}"
-
-desktop_install_url="https://www.docker.com/products/docker-desktop"
-engine_install_url="https://docs.docker.com/get-docker/"
-
-link_path="/usr/local/bin/${LINK_NAME}"
-existing_cli_path="/usr/bin/docker"
-
-manual_install() {
- echo "Please follow the manual install instructions"
-}
-
-is_new_cli() {
- cloud_version_str="$($1 version 2>/dev/null | grep 'Cloud integration' || true)"
- if [ -n "$cloud_version_str" ]; then
- echo 1
- else
- azure_version_str="$($1 version 2>/dev/null | grep 'Azure' || true)"
- if [ -n "$azure_version_str" ]; then
- echo 1
- fi
- echo 0
- fi
-}
-
-echo "Running checks..."
-
-# Check OS
-if [ "$(command -v uname)" ]; then
- case "$(uname -s)" in
- "Linux")
- # Check for Ubuntu/Debian based distro
- if ! [ -f "/etc/lsb-release" ]; then
- echo "Warning: This script has been tested on Ubuntu and may not work on other distributions"
- fi
- # Pass
- ;;
- "Darwin")
- echo "Error: Script not needed on macOS, please install Docker Desktop Edge: $desktop_install_url"
- exit 1
- ;;
- "*")
- echo "Error: Unsupported OS, please follow manual instructions"
- exit 1
- ;;
- esac
-else
- # Assume Windows
- echo "Error: Script not needed on Windows, please install Docker Desktop Edge: $desktop_install_url"
- exit 1
-fi
-
-user="$(id -un 2>/dev/null || true)"
-sh_c='sh -c'
-sudo_sh_c='sh -c'
-if [ "$user" != 'root' ]; then
- if [ "$(command -v sudo)" ]; then
- sudo_sh_c='sudo -E sh -c'
- elif [ "$(command -v su)" ]; then
- sudo_sh_c='su -c'
- else
- echo "Error: This installer needs the ability to run commands as root."
- exit 1
- fi
-fi
-
-if [ -n "$DRY_RUN" ]; then
- sh_c='echo $sh_c'
- sudo_sh_c='echo $sudo_sh_c'
-fi
-
-# Check if Docker Engine is installed
-if ! [ "$(command -v docker)" ]; then
- echo "Error: Docker Engine not found"
- echo "You need to install Docker first: $engine_install_url"
- exit 1
-fi
-
-download_cmd='curl -fsSLo'
-# Check that system has curl installed
-if ! [ "$(command -v curl)" ]; then
- echo "Error: curl not found"
- echo "Please install curl"
- exit 1
-fi
-
-if [ "$(uname -m)" = "aarch64" ]; then
- DOWNLOAD_URL=${DOWNLOAD_URL:-$(curl -s ${RELEASE_URL} | grep "browser_download_url.*docker-linux-arm64" | cut -d : -f 2,3)}
-elif [ "$(uname -m)" = "s390x" ]; then
- DOWNLOAD_URL=${DOWNLOAD_URL:-$(curl -s ${RELEASE_URL} | grep "browser_download_url.*docker-linux-s390x" | cut -d : -f 2,3)}
-else
- DOWNLOAD_URL=${DOWNLOAD_URL:-$(curl -s ${RELEASE_URL} | grep "browser_download_url.*docker-linux-amd64" | cut -d : -f 2,3)}
-fi
-
-# Check if the Compose CLI is already installed
-if [ $(is_new_cli "docker") -eq 1 ]; then
- if [ $(is_new_cli "/usr/local/bin/docker") -eq 1 ]; then
- echo "You already have the Docker Compose CLI installed, overriding with latest version"
- download_dir=$($sh_c 'mktemp -d')
- $sh_c "${download_cmd} ${download_dir}/docker ${DOWNLOAD_URL}"
- $sudo_sh_c "install -m 775 ${download_dir}/docker /usr/local/bin/docker"
- exit 0
- fi
- echo "You already have the Docker Compose CLI installed, in a different location."
- exit 1
-fi
-
-# Check if this script has already been run
-if [ -f "${link_path}" ]; then
- echo "Error: This script appears to have been run as ${link_path} exists"
- echo "Please uninstall and rerun this script or follow the manual instructions"
- exit 1
-fi
-
-# Check current Docker CLI is installed to /usr/bin/
-if ! [ -f "${existing_cli_path}" ]; then
- echo "Error: This script only works if the Docker CLI is installed to /usr/bin/"
- manual_install
- exit 1
-fi
-
-# Check that PATH contains /usr/bin and /usr/local/bin and that the latter is
-# higher priority
-path_directories=$(echo "${PATH}" | tr ":" "\n")
-usr_bin_pos=-1
-usr_local_bin_pos=-1
-count=0
-for d in ${path_directories}; do
- if [ "${d}" = '/usr/bin' ]; then
- usr_bin_pos=$count
- fi
- if [ "${d}" = '/usr/local/bin' ]; then
- usr_local_bin_pos=$count
- fi
- count=$((count + 1))
-done
-if [ $usr_bin_pos -eq -1 ]; then
- echo "Error: /usr/bin not found in PATH"
- manual_install
- exit 1
-elif [ $usr_local_bin_pos -eq -1 ]; then
- echo "Error: /usr/local/bin not found in PATH"
- manual_install
- exit 1
-elif ! [ $usr_local_bin_pos -lt $usr_bin_pos ]; then
- echo "Error: /usr/local/bin is not ordered higher than /usr/bin in your PATH"
- manual_install
- exit 1
-fi
-
-echo "Checks passed!"
-echo "Downloading CLI..."
-
-# Download CLI to temporary directory
-download_dir=$($sh_c 'mktemp -d')
-$sh_c "${download_cmd} ${download_dir}/docker ${DOWNLOAD_URL}"
-
-echo "Downloaded CLI!"
-echo "Installing CLI..."
-
-# Link existing Docker CLI
-$sudo_sh_c "ln -s ${existing_cli_path} ${link_path}"
-
-# Install downloaded CLI
-$sudo_sh_c "install -m 775 ${download_dir}/docker /usr/local/bin/docker"
-
-# Clear cache
-cleared_cache=1
-if [ "$(command hash)" ]; then
- $sh_c "hash -r"
-elif [ "$(command rehash)" ]; then
- $sh_c "rehash"
-else
- cleared_cache=
- echo "Warning: Unable to clear command cache"
-fi
-
-if [ -n "$DRY_RUN" ]; then
- exit 0
-fi
-
-if [ -n "$cleared_cache" ]; then
- # Check Compose CLI is working
- if [ $(is_new_cli "docker") -eq 0 ]; then
- echo "Error: Docker Compose CLI installation error"
- exit 1
- fi
- echo "Done!"
-else
- echo "Please log out and in again to use the Docker Compose CLI"
-fi
diff --git a/scripts/install/test.Dockerfile b/scripts/install/test.Dockerfile
deleted file mode 100644
index c19caebe..00000000
--- a/scripts/install/test.Dockerfile
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2020 Docker Compose CLI authors
-
-# 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.
-
-# Distro options: ubuntu, centos
-ARG DISTRO=ubuntu
-
-FROM ubuntu:20.04 AS base-ubuntu
-RUN apt-get update && apt-get install -y \
- curl
-RUN curl https://get.docker.com | sh
-
-FROM centos:7 AS base-centos
-RUN curl https://get.docker.com | sh
-
-FROM base-${DISTRO} AS install
-
-RUN apt-get update && apt-get -y install sudo
-RUN adduser --disabled-password --gecos '' newuser
-RUN adduser newuser sudo
-RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
-USER newuser
-WORKDIR /home/newuser
-
-COPY install_linux.sh /scripts/install_linux.sh
-RUN sudo chmod +x /scripts/install_linux.sh
-ARG DOWNLOAD_URL=
-RUN DOWNLOAD_URL=${DOWNLOAD_URL} /scripts/install_linux.sh
-RUN docker version | grep Cloud
-
-FROM install AS upgrade
-
-USER newuser
-WORKDIR /home/newuser
-
-RUN DOWNLOAD_URL=${DOWNLOAD_URL} /scripts/install_linux.sh
-RUN docker version | grep Cloud
-
-# To run this test locally, start an HTTP server that serves the dist/ folder
-# then run a docker build passing the DOWNLOAD_URL as a build arg:
-# $ cd dist/ && python3 -m http.server &
-# $ docker build -f test.Dockerfile --build-arg DOWNLOAD_URL=http://192.168.0.22:8000/docker-linux-amd64.tar.gz .
-#
-# You can specify centos or ubuntu as distros using the DISTRO build arg.
diff --git a/scripts/validate/check-go-mod b/scripts/validate/check-go-mod
deleted file mode 100755
index ad45b563..00000000
--- a/scripts/validate/check-go-mod
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-# Copyright Docker Compose CLI authors
-
-# 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.
-
-
-set -uo pipefail
-mkdir -p /tmp/gomod
-cp go.* /tmp/gomod/
-go mod tidy
-DIFF=$(diff go.mod /tmp/gomod/go.mod && diff go.sum /tmp/gomod/go.sum)
-if [ "$DIFF" ]; then
- echo
- echo "go.mod and go.sum are not up to date"
- echo
- echo "$DIFF"
- echo
- exit 1
-else
- echo "go.mod is correct"
-fi;
diff --git a/scripts/validate/fileheader b/scripts/validate/fileheader
deleted file mode 100755
index 4f5dc027..00000000
--- a/scripts/validate/fileheader
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env sh
-
-# Copyright 2020, 2022 Docker Compose CLI authors
-
-# 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.
-
-set -eu -o pipefail
-
-if ! command -v addlicense; then
- >&2 echo "ERROR: addlicense not found. Install with:"
- >&2 echo " go install github.com/google/addlicense@latest"
- exit 1
-fi
-
-find . -regex '.*\.sh' -o -regex '.*\.go' -o -regex '.*Makefile' -o -regex '.*Dockerfile' | xargs addlicense -check -l apache -c 'Docker Compose CLI authors' -ignore validate -ignore testdata -ignore resolvepath -v 1>&2
diff --git a/utils/check.go b/utils/check.go
deleted file mode 100644
index a3256bce..00000000
--- a/utils/check.go
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 utils
-
-import (
- "context"
- "fmt"
-
- "github.com/docker/compose/v2/pkg/api"
- "github.com/hashicorp/go-multierror"
- "github.com/pkg/errors"
-)
-
-// CheckUnsupported checks if a flag was used when it shouldn't and adds an error in case
-func CheckUnsupported(ctx context.Context, errs error, toCheck, expectedValue interface{}, commandName, msg string) error {
- if !(isNil(toCheck) && isNil(expectedValue)) && toCheck != expectedValue {
- return multierror.Append(errs, errors.Wrap(api.ErrUnsupportedFlag,
- fmt.Sprintf(`option "%s --%s"`, commandName, msg)))
- }
- return errs
-}
diff --git a/utils/logs.go b/utils/logs.go
deleted file mode 100644
index b7ab58a3..00000000
--- a/utils/logs.go
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 utils
-
-import (
- "github.com/docker/compose/v2/pkg/api"
-)
-
-// FilteredLogConsumer filters logs for given services
-func FilteredLogConsumer(consumer api.LogConsumer, services []string) api.LogConsumer {
- if len(services) == 0 {
- return consumer
- }
- allowed := map[string]bool{}
- for _, s := range services {
- allowed[s] = true
- }
- return &allowListLogConsumer{
- allowList: allowed,
- delegate: consumer,
- }
-}
-
-type allowListLogConsumer struct {
- allowList map[string]bool
- delegate api.LogConsumer
-}
-
-func (a *allowListLogConsumer) Log(container, service, message string) {
- if a.allowList[service] {
- a.delegate.Log(container, service, message)
- }
-}
-
-func (a *allowListLogConsumer) Status(container, message string) {
- if a.allowList[container] {
- a.delegate.Status(container, message)
- }
-}
-
-func (a *allowListLogConsumer) Register(name string) {
- if a.allowList[name] {
- a.delegate.Register(name)
- }
-}
diff --git a/utils/units.go b/utils/units.go
deleted file mode 100644
index 5ba4661f..00000000
--- a/utils/units.go
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 utils
-
-import (
- "reflect"
-
- "github.com/docker/go-units"
-)
-
-// MemBytes is a type for human readable memory bytes (like 128M, 2g, etc)
-type MemBytes int64
-
-// String returns the string format of the human readable memory bytes
-func (m *MemBytes) String() string {
- // NOTE: In spf13/pflag/flag.go, "0" is considered as "zero value" while "0 B" is not.
- // We return "0" in case value is 0 here so that the default value is hidden.
- // (Sometimes "default 0 B" is actually misleading)
- if m.Value() != 0 {
- return units.BytesSize(float64(m.Value()))
- }
- return "0"
-}
-
-// Set sets the value of the MemBytes by passing a string
-func (m *MemBytes) Set(value string) error {
- val, err := units.RAMInBytes(value)
- *m = MemBytes(val)
- return err
-}
-
-// Type returns the type
-func (m *MemBytes) Type() string {
- return "bytes"
-}
-
-// Value returns the value in int64
-func (m *MemBytes) Value() int64 {
- return int64(*m)
-}
-
-func isNil(i interface{}) bool {
- if i == nil {
- return true
- }
- switch reflect.TypeOf(i).Kind() {
- case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice:
- return reflect.ValueOf(i).IsNil()
- }
- return false
-}
diff --git a/utils/units_test.go b/utils/units_test.go
deleted file mode 100644
index 2e35e11b..00000000
--- a/utils/units_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- Copyright 2020 Docker Compose CLI authors
-
- 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 utils
-
-import (
- "testing"
-
- "gotest.tools/v3/assert"
- "gotest.tools/v3/assert/cmp"
-)
-
-const (
- b = 1
- kb = 1024 * b
- mb = 1024 * kb
- gb = 1024 * mb
-)
-
-func TestMemBytes(t *testing.T) {
- var m MemBytes
- assert.Assert(t, cmp.Nil(m.Set("42")))
- assert.Equal(t, int64(42), m.Value())
- assert.Equal(t, "42B", m.String())
-
- assert.Assert(t, cmp.Nil(m.Set("1b")))
- assert.Equal(t, int64(1), m.Value())
- assert.Equal(t, "1B", m.String())
-
- assert.Assert(t, cmp.Nil(m.Set("1k")))
- assert.Equal(t, int64(kb), m.Value())
- assert.Equal(t, "1KiB", m.String())
-
- assert.Assert(t, cmp.Nil(m.Set("1m")))
- assert.Equal(t, int64(mb), m.Value())
- assert.Equal(t, "1MiB", m.String())
-
- assert.Assert(t, cmp.Nil(m.Set("1g")))
- assert.Equal(t, int64(gb), m.Value())
- assert.Equal(t, "1GiB", m.String())
-
- assert.Assert(t, cmp.Nil(m.Set("42g")))
- assert.Equal(t, int64(42*gb), m.Value())
- assert.Equal(t, "42GiB", m.String())
-
- assert.Error(t, m.Set("###"), "invalid size: '###'")
-}