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: '###'") -}