From 04b4fde0e03f0e9b7bc53e189b07b96bc9d52bb2 Mon Sep 17 00:00:00 2001 From: Austin Drenski Date: Mon, 12 Feb 2024 19:08:18 -0500 Subject: [PATCH] Strip down to bare bones --- .dockerignore | 5 +- .gitattributes | 2 - .github/workflows/ci.yml | 5 +- .github/workflows/ecs-tests.yml | 36 - .github/workflows/labeler.yml | 13 - .gitignore | 4 +- .golangci.yml | 33 - BUILDING.md | 82 - CONTRIBUTING.md | 326 ---- Dockerfile | 124 +- INSTALL.md | 106 -- MAINTAINERS | 57 - Makefile | 107 -- NOTICE | 4 - README.md | 2 +- builder.Makefile | 88 -- cli/main.go | 69 - cmd/main.go | 33 + docker-bake.hcl | 54 + docs/ecs-architecture.md | 82 - docs/ecs-compose-examples.md | 302 ---- docs/ecs-compose-features.md | 181 --- ecs/autoscaling.go | 128 -- ecs/autoscaling_test.go | 43 - ecs/aws.go | 77 - ecs/awsResources.go | 518 ------- ecs/aws_mock.go | 697 --------- ecs/backend.go | 161 -- ecs/cloudformation.go | 1053 ++++++++----- ecs/cloudformation_test.go | 363 +---- ecs/compatibility.go | 179 --- ecs/convert.go | 593 -------- ecs/doc.go | 17 - ecs/down.go | 107 -- ecs/e2e/ecs/compose.yaml | 21 +- ecs/e2e/ecs/e2e-ecs_test.go | 49 - ecs/e2e/ecs/my_secret1.txt | 1 - ecs/ec2.go | 132 -- ecs/ec2_test.go | 49 - ecs/gpu.go | 253 ---- ecs/gpu_test.go | 115 -- ecs/iam.go | 110 -- ecs/list.go | 125 -- ecs/logs.go | 53 - ecs/marshall.go | 78 - ecs/notimplemented.go | 96 -- ecs/ps.go | 68 - ecs/resolv/Dockerfile | 22 - ecs/resolv/main/main.go | 39 - ecs/resolv/resolv.go | 35 - ecs/resolv/resolv_test.go | 47 - ecs/resolv/testdata/resolv.conf.golden | 2 - ecs/sdk.go | 1159 +------------- ecs/secrets.go | 39 - ecs/secrets/Dockerfile | 22 - ecs/secrets/init.go | 104 -- ecs/secrets/init_test.go | 103 -- ecs/secrets/main/main.go | 49 - ecs/service.go | 226 +++ ecs/tags.go | 58 - ecs/testdata/context-by-keys-config.golden | 2 - .../context-by-keys-credentials.golden | 3 - ecs/testdata/context-by-profile-config.golden | 3 - .../context-by-profile-credentials.golden | 4 - ecs/testdata/input/envfile | 1 - ecs/testdata/input/simple-single-service.yaml | 5 - ecs/testdata/invalid_network_mode.yaml | 4 - .../simple-cloudformation-conversion.golden | 208 --- ecs/up.go | 122 -- ecs/volumes.go | 155 -- ecs/wait.go | 123 -- ecs/wait_test.go | 27 - ecs/x.go | 34 - go.mod | 224 ++- go.sum | 1349 ++++------------- internal/variables.go | 22 - packaging/LICENSE | 2 - samples/compose.ecs.yml | 74 + samples/compose.local.yml | 22 + samples/compose.yml | 27 + scripts/install/install_linux.sh | 213 --- scripts/install/test.Dockerfile | 54 - scripts/validate/check-go-mod | 32 - scripts/validate/fileheader | 25 - utils/check.go | 35 - utils/logs.go | 59 - utils/units.go | 65 - utils/units_test.go | 60 - 88 files changed, 1610 insertions(+), 10050 deletions(-) delete mode 100644 .gitattributes delete mode 100644 .github/workflows/ecs-tests.yml delete mode 100644 .github/workflows/labeler.yml delete mode 100644 .golangci.yml delete mode 100644 BUILDING.md delete mode 100644 CONTRIBUTING.md delete mode 100644 INSTALL.md delete mode 100644 MAINTAINERS delete mode 100644 Makefile delete mode 100644 NOTICE delete mode 100644 builder.Makefile delete mode 100644 cli/main.go create mode 100644 cmd/main.go create mode 100644 docker-bake.hcl delete mode 100644 docs/ecs-architecture.md delete mode 100644 docs/ecs-compose-examples.md delete mode 100644 docs/ecs-compose-features.md delete mode 100644 ecs/autoscaling.go delete mode 100644 ecs/autoscaling_test.go delete mode 100644 ecs/aws.go delete mode 100644 ecs/awsResources.go delete mode 100644 ecs/aws_mock.go delete mode 100644 ecs/backend.go delete mode 100644 ecs/compatibility.go delete mode 100644 ecs/convert.go delete mode 100644 ecs/doc.go delete mode 100644 ecs/down.go delete mode 100644 ecs/e2e/ecs/my_secret1.txt delete mode 100644 ecs/ec2.go delete mode 100644 ecs/ec2_test.go delete mode 100644 ecs/gpu.go delete mode 100644 ecs/gpu_test.go delete mode 100644 ecs/iam.go delete mode 100644 ecs/list.go delete mode 100644 ecs/logs.go delete mode 100644 ecs/marshall.go delete mode 100644 ecs/notimplemented.go delete mode 100644 ecs/ps.go delete mode 100644 ecs/resolv/Dockerfile delete mode 100644 ecs/resolv/main/main.go delete mode 100644 ecs/resolv/resolv.go delete mode 100644 ecs/resolv/resolv_test.go delete mode 100644 ecs/resolv/testdata/resolv.conf.golden delete mode 100644 ecs/secrets.go delete mode 100644 ecs/secrets/Dockerfile delete mode 100644 ecs/secrets/init.go delete mode 100644 ecs/secrets/init_test.go delete mode 100644 ecs/secrets/main/main.go create mode 100644 ecs/service.go delete mode 100644 ecs/tags.go delete mode 100644 ecs/testdata/context-by-keys-config.golden delete mode 100644 ecs/testdata/context-by-keys-credentials.golden delete mode 100644 ecs/testdata/context-by-profile-config.golden delete mode 100644 ecs/testdata/context-by-profile-credentials.golden delete mode 100644 ecs/testdata/input/envfile delete mode 100644 ecs/testdata/input/simple-single-service.yaml delete mode 100644 ecs/testdata/invalid_network_mode.yaml delete mode 100644 ecs/testdata/simple-cloudformation-conversion.golden delete mode 100644 ecs/up.go delete mode 100644 ecs/volumes.go delete mode 100644 ecs/wait.go delete mode 100644 ecs/wait_test.go delete mode 100644 ecs/x.go delete mode 100644 internal/variables.go delete mode 100644 packaging/LICENSE create mode 100644 samples/compose.ecs.yml create mode 100644 samples/compose.local.yml create mode 100644 samples/compose.yml delete mode 100644 scripts/install/install_linux.sh delete mode 100644 scripts/install/test.Dockerfile delete mode 100755 scripts/validate/check-go-mod delete mode 100755 scripts/validate/fileheader delete mode 100644 utils/check.go delete mode 100644 utils/logs.go delete mode 100644 utils/units.go delete mode 100644 utils/units_test.go 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..74510048 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 'github.com/austindrenski/compose-ecs/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: '###'") -}